Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine if a given int64_t can be stored losslessly in a double?

Tags:

c++

precision

I'd like to determine if a given 64-bit integer can be stored losslessly in a double. Right now I have this code:

static_cast<int64_t>(static_cast<double>(value)) == value

However, I believe this is not always accurate due to excess precision on some platforms.

Note that I'm not asking for the largest integer such that all smaller integers can be stored losslessly, which is 2^53. I need to know if a given integer N is losslessly storeable even if N+1 and N-1 are not.

Is there something in the standard library, maybe similar to std::numeric_limits, that will tell me this?

like image 389
ptomato Avatar asked Mar 01 '17 20:03

ptomato


People also ask

Is Int64 a double?

Int64 (aka long): A signed integer with 64 bits (8 bytes) of space available. Single (aka float): A 32-bit floating point number. Double (aka double): A 64-bit floating-point number. Decimal (aka decimal): A 128-bit floating-point number with a higher precision and a smaller range than Single or Double.

Should I use long long or int64_t?

If long long is present, it must have at least 64 bits, so casting from (u)int64_t to (unsigned) long long is value-preserving. If you need a type with exactly 64 bits, use (u)int64_t , if you need at least 64 bits, (unsigned) long long is perfectly fine, as would be (u)int_least64_t .

Is int64_t a long?

In a 64-bit compile, int64_t is long int , not a long long int (obviously).

What is int64_t data type in C++?

A long on some systems is 32 bits (same as an integer), the int64_t is defined as a 64 bit integer on all systems (otherwise known as a long long). Portability may be affected using long, but using int64_t looks like it was created to increase portability.


1 Answers

As long as low bits are 0, you can have more high order bits set (because you can increase the double's exponent). I reduced the requirement to unsigned to make the bit shifting not have to worry about sign bits but I believe it should be adaptable.

bool fits_in_double_losslessly (uint64_t v)
{
    const uint64_t largest_int = 1ULL << 53;

    while ((v > largest_int) && !(v & 1))
    {
        v >>= 1;
    }

    return v <= largest_int;
}
like image 176
Mark B Avatar answered Sep 25 '22 15:09

Mark B