Intel® ISA Extensions
Use hardware-based isolation and memory encryption to provide more code protection in your solutions.
Announcements
Welcome to the Intel Community. If you get an answer you like, please mark it as an Accepted Solution to help others. Thank you!
For the latest information on Intel’s response to the Log4j/Log4Shell vulnerability, please see Intel-SA-00646
1052 Discussions

Check if a floating point is actually an Integer

anujgarg2004gmail_co
203 Views

i need a method which given a floating point can check whether it is actually an integral value or not. Currently i am using something like this.

bool IsInteger(double dbl)

{

long lwT = (long)dbl;
double dblT = (double)lwT;
return (LowerDWORD(dblT) == LowerDWORD(dbl) && HigherDWORD(dblT) == HigherDWORD(dbl));

}

This method happens to consume 50% of my time blaming _ftol2_sse and floor functions.

Is there any better method to do this? Any assembly instruction possibly?

0 Kudos
1 Solution
ILevi1
Valued Contributor I
203 Views
I presume this is what you want:
[cpp]bool IsInteger(double dVal)
{
	__int64	iVal = (__int64)dVal;
	double	tVal = (double)iVal;
	return (tVal == dVal) ? true : false;
}
[/cpp]
You can try to use this code as well:
[cpp]bool IsInteger(double dVal)
{
const	double	magic = 68719476736.0 * 1.5;
	double	tVal1 = dVal + magic;
	int	iVal = ((int*)&tVal1)[0] >> 16;
	double	tVal2 = iVal;
	return (tVal2 == dVal) ? true : false;
}
[/cpp]
However, in a quick test I just performed the following code seems to be the fastest:
[cpp]bool IsInteger(double dVal)
{
	int	iVal = (int)dVal;
	double	tVal = (double)iVal;
	return (tVal == dVal) ? true : false;
}
[/cpp]
That is of course assuming that your double will never exceed the range of a 32-bit integer.

View solution in original post

9 Replies
TimP
Black Belt
203 Views

i need a method which given a floating point can check whether it is actually an integral value or not. Currently i am using something like this.

bool IsInteger(double dbl)

{

long lwT = (long)dbl;
double dblT = (double)lwT;
return (LowerDWORD(dblT) == LowerDWORD(dbl) && HigherDWORD(dblT) == HigherDWORD(dbl));

}

This method happens to consume 50% of my time blaming _ftol2_sse and floor functions.

Is there any better method to do this? Any assembly instruction possibly?


There must be something you haven't told us, to explain why you would do something so convoluted.
dblT == dbl
looks like it makes more sense.
dbl == rint(dbl)
or even (if using SSE2)
dbl == (long int)dbl
(depending on what you mean by integral values)
might be faster, if you don't need to support old compilers, or can use equivalent in-line asm.
anujgarg2004gmail_co
203 Views
Quoting - tim18

There must be something you haven't told us, to explain why you would do something so convoluted.
dblT == dbl
looks like it makes more sense.
dbl == rint(dbl)
or even (if using SSE2)
dbl == (long int)dbl
(depending on what you mean by integral values)
might be faster, if you don't need to support old compilers, or can use equivalent in-line asm.

By integral value i mean that if there is something of the sort 23.000000000 then it is integral for me (digits of presion depends maximum size of INT32.

this whole converting to INT/LONG is kinda expensive. i was wondering if there is some assembly instruction similar to that of rint(). Unfortunately there is no rint() on windows. Do you know any workaround?

Isn't rint() same as (mantisa = mantisa & (0xFFFFFFFF << (53 - ( 127 - exp )))

so in that case instead of a typecast i can simple do a couple of Bit operations. Do you think it will be cheaper than typecasting ?

TimP
Black Belt
203 Views

You hinted that you might use /arch:SSE2 (or X64, where that is the default).Changing rounding mode to make an (long int) castwould be quite expensive in original x87 code. So, you really need to decide about such instruction set issues, if you want to optimize performance.
One point about the difference between rint() and (long int) is that the former admits of integral values which exceed LONG_MAX.If you exclude operation on such values, and choose SSE2, you don't really need rint(). Particulary on a forum meant for future instruction sets, it is a bit out of place to insist you won't use a compiler from this century. At least, I have no intention of going there without current compiler support.
If you do want to handle numbers beyond LONG_MAX, and want to write your own replacement for rint(), using SSE2 code generation, for 0 < x < 1/DBL_EPSILON, ((x + 1/DBL_EPSILON) - 1/DBL/EPSILON) will work, if you use a C89 compiler. For negative values, you just change the sign, and for |x| > 1/DBL_EPSILON you know that it is already an integral value.
ILevi1
Valued Contributor I
204 Views
I presume this is what you want:
[cpp]bool IsInteger(double dVal)
{
	__int64	iVal = (__int64)dVal;
	double	tVal = (double)iVal;
	return (tVal == dVal) ? true : false;
}
[/cpp]
You can try to use this code as well:
[cpp]bool IsInteger(double dVal)
{
const	double	magic = 68719476736.0 * 1.5;
	double	tVal1 = dVal + magic;
	int	iVal = ((int*)&tVal1)[0] >> 16;
	double	tVal2 = iVal;
	return (tVal2 == dVal) ? true : false;
}
[/cpp]
However, in a quick test I just performed the following code seems to be the fastest:
[cpp]bool IsInteger(double dVal)
{
	int	iVal = (int)dVal;
	double	tVal = (double)iVal;
	return (tVal == dVal) ? true : false;
}
[/cpp]
That is of course assuming that your double will never exceed the range of a 32-bit integer.

View solution in original post

capens__nicolas
New Contributor I
203 Views
Here's another approach:

bool __declspec(noinline) isInteger(double x)
{
__int64 binary = (__int64&)x;
int exponent = (int)((binary & 0x7FF0000000000000) >> 52) - 1023;
__int64 mantissa = (binary & 0x000FFFFFFFFFFFFF) | 0x0010000000000000;
__int64 decimals = (exponent >= 0) ? 0x000FFFFFFFFFFFFF >> exponent : 0x001FFFFFFFFFFFFF;

return x == 0.0 || !(mantissa & decimals);
}

It should also work for integers that don't fit in the 64-bit range. I haven't checked the behavior for denormals and NaNs so you might want to test that.

It works by testing whether any of the mantissa bits below the decimal point are set. It should perform quite well, although it won't be as fast as an SSE2 conversion back and forth.
capens__nicolas
New Contributor I
203 Views
Please ignore the __declspec(noinline) part, I used it to check the generated assembly code. Updated version with syntax highlighting:
[cpp]bool isInteger(double x)
{
	__int64 binary = (__int64&)x;
	int exponent = (int)((binary & 0x7FF0000000000000) >> 52) - 1023;
	__int64 mantissa = (binary & 0x000FFFFFFFFFFFFF) | 0x0010000000000000;
	__int64 decimals = (exponent >= 0) ? 0x000FFFFFFFFFFFFF >> exponent : 0x001FFFFFFFFFFFFF;

	return x == 0.0 || !(mantissa & decimals);
}[/cpp]
anujgarg2004gmail_co
203 Views
Quoting - Igor Levicki
I presume this is what you want:
[cpp]bool IsInteger(double dVal)
{
	__int64	iVal = (__int64)dVal;
	double	tVal = (double)iVal;
	return (tVal == dVal) ? true : false;
}
[/cpp]
You can try to use this code as well:
[cpp]bool IsInteger(double dVal)
{
const	double	magic = 68719476736.0 * 1.5;
	double	tVal1 = dVal + magic;
	int	iVal = ((int*)&tVal1)[0] >> 16;
	double	tVal2 = iVal;
	return (tVal2 == dVal) ? true : false;
}
[/cpp]
However, in a quick test I just performed the following code seems to be the fastest:
[cpp]bool IsInteger(double dVal)
{
	int	iVal = (int)dVal;
	double	tVal = (double)iVal;
	return (tVal == dVal) ? true : false;
}
[/cpp]
That is of course assuming that your double will never exceed the range of a 32-bit integer.


the last code is exactly was i was doing. it seemed to be a bit to expensive in the begining but after some experimentations with all of these mentioned stratergies, i realized this one is indeed the best. Thanx for all your replies.
TimP
Black Belt
203 Views

the last code is exactly was i was doing. it seemed to be a bit to expensive in the begining but after some experimentations with all of these mentioned stratergies, i realized this one is indeed the best. Thanx for all your replies.
Casting double to int and back to double would be quite slow in x87 code, but no problem in other common instruction sets, within the range limitations.
ILevi1
Valued Contributor I
203 Views

the last code is exactly was i was doing. it seemed to be a bit to expensive in the begining but after some experimentations with all of these mentioned stratergies, i realized this one is indeed the best. Thanx for all your replies.

You are welcome. If you find my reply helpfull please don't forget to rate my post and/or select it as a best answer. Thank you.

Reply