I'm looking to for a reasonably efficient way of determining if a floating point value (double
) can be exactly represented by an integer data type (long
, 64 bit).
My initial thought was to check the exponent to see if it was 0
(or more precisely 127
). But that won't work because 2.0
would be e=1 m=1...
So basically, I am stuck. I have a feeling that I can do this with bit masks, but I'm just not getting my head around how to do that at this point.
So how can I check to see if a double is exactly representable as a long?
Thanks
Check if float is integer: is_integer() float has is_integer() method that returns True if the value is an integer, and False otherwise. For example, a function that returns True for an integer number ( int or integer float ) can be defined as follows. This function returns False for str .
If you have a number of reasonable magnitude with only a few significant digits in its decimal representation, then if it passes this test it is exactly representable.
Real numbers are represented in C by the floating point types float, double, and long double. Just as the integer types can't represent all integers because they fit in a bounded number of bytes, so also the floating-point types can't represent all real numbers.
The Number. isInteger() method returns true if a value is an integer of the datatype Number. Otherwise it returns false .
Here's one method that could work in most cases. I'm not sure if/how it will break if you give it NaN
, INF
, very large (overflow) numbers...
(Though I think they will all return false - not exactly representable.)
You could:
Something like this:
double val = ... ; // Value
if ((double)(long long)val == val){
// Exactly representable
}
floor()
and ceil()
are also fair game (though they may fail if the value overflows an integer):
floor(val) == val
ceil(val) == val
And here's a messy bit-mask solution:
This uses union type-punning and assumes IEEE double-precision. Union type-punning is only valid in C99 TR2 and later.
int representable(double x){
// Handle corner cases:
if (x == 0)
return 1;
// -2^63 is representable as a signed 64-bit integer, but +2^63 is not.
if (x == -9223372036854775808.)
return 1;
// Warning: Union type-punning is only valid in C99 TR2 or later.
union{
double f;
uint64_t i;
} val;
val.f = x;
uint64_t exp = val.i & 0x7ff0000000000000ull;
uint64_t man = val.i & 0x000fffffffffffffull;
man |= 0x0010000000000000ull; // Implicit leading 1-bit.
int shift = (exp >> 52) - 1075;
// Out of range
if (shift < -52 || shift > 10)
return 0;
// Test mantissa
if (shift < 0){
shift = -shift;
return ((man >> shift) << shift) == man;
}else{
return ((man << shift) >> shift) == man;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With