为什么(长)9223372036854665200d给我9223372036854665216?

我知道有精确错误的怪异东西,但我无法理解,

为什么(long)9223372036854665200d给我9223372036854665216

9223372036854665200ddouble类型的常量。 但是, 9223372036854665200不适合double精度而不会损失精度。 double只有52位尾数,而有问题的数字需要精确表示63位。

距离9223372036854665200d最近的一个是尾数等于1.1111111111111111111111111111111111111111111110010100二进制且其指数为63(十进制)的数字。 这个数字不是别的,而是9223372036854665216 (称之为U )。

如果我们将尾数减少一个等级到1.1...0011 ,我们得到9223372036854664192 (称之为L )。

原始数字在LU之间,并且比L更接近于U

最后,如果你认为这个尾数的截断应该导致一个以一串零结尾的数字,那么你是对的。 只有它以二进制forms出现,而不是十进制:基数为16的U0x7ffffffffffe5000L0x7ffffffffffe4c00

因为双打没那么精确。 你为什么这么奇怪? 将d更改为l。

Doubles精度具有52-53位精度,而long具有64位精度(仅适用于整数)。 double中的精度损失用于表示指数,这允许double表示比long can更大/更小的数字。

您的号码长度为19位,而双号码只能存储大约16位数的(十进制)整数数据。 因此,最终的数字最终被舍入。

参考: 双 – 维基百科

因为双打精度有限。 你的常数有一个比双重记录更多的有效数字,所以它失去了它们。

您假设有限精度意味着它以十进制表示,因此限制为15或16位数。 实际上它以二进制表示,并且限制为53位精度。 double取最接近的可表示值。

 double d = 9223372036854665200d; System.out.println(d +" is actually\n" + new BigDecimal(d)+" so when cast to (long) is\n"+(long) d); 

版画

 9.2233720368546652E18 is actually 9223372036854665216 so when cast to (long) is 9223372036854665216