简体   繁体   中英

Value change when converting a long to a double and back

given the following code:

long l = 1234567890123;
double d = (double) l;

is the following expression guaranteed to be true?

l == (long) d

I should think no, because as numbers get larger, the gaps between two doubles grow beyond 1 and therefore the conversion back yields a different long value. In case the conversion does not take the value that's greater than the long value, this might also happen earlier.

Is there a definitive answer to that?

Nope, absolutely not. There are plenty of long values which aren't exactly representable by double . In fact, that has to be the case, given that both types are represented in 64 bits, and there are obviously plenty of double values which aren't representable in long (eg 0.5)

Simple example (Java and then C#):

// Java
class Test {
    public static void main(String[] args) {
        long x = Long.MAX_VALUE - 1;
        double d = x;
        long y = (long) d;
        System.out.println(x == y);
    }
}

// C#
using System;

class Test
{
    static void Main()
    {
        long x = long.MaxValue;
        double d = x;
        long y = (long) d;
        Console.WriteLine(x == y);
    }
}

I observed something really strange when doing this though... in C#, long.MaxValue "worked" in terms of printing False... whereas in Java, I had to use Long.MAX_VALUE - 1 . My guess is that this is due to some inlining and 80-bit floating point operations in some cases... but it's still odd :)

My code started with 0 and incremented by 100,000,000. The smallest number that failed the test was found to be 2,305,843,009,300,000,000 (19 digits). So, any positive long less than 2,305,843,009,200,000,000 is representable exactly by doubles. In particular, 18-digit longs are also representable exactly by doubles.

By the way, the reason I was interested in this question is that I wondered if I can use doubles to represent timestamps (in milliseconds). Since current timestamps are on the order of 13 digits (and it will take for them rather long time to get to 18 digits), I'll do that.

You can test this as there are a finite number of long values.

for (long l = Long.MIN_VALUE; l<Long.MAX_VALUE; l++)
{
  double d = (double) l;
  if (l == (long)d)
  {
    System.out.println("long " + l + " fails test");
  }
}

Doesn't take many iterations to prove that;

l = -9223372036854775805
d = -9.223372036854776E18
(long)d = -9223372036854775808

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM