为什么(长)9223372036854665200d给我9223372036854665216?
我知道有精确错误的怪异东西,但我无法理解,
为什么(long)9223372036854665200d
给我9223372036854665216
?
9223372036854665200d
是double
类型的常量。 但是, 9223372036854665200
不适合double
精度而不会损失精度。 double
只有52位尾数,而有问题的数字需要精确表示63位。
距离9223372036854665200d
最近的一个是尾数等于1.1111111111111111111111111111111111111111111110010100
二进制且其指数为63(十进制)的数字。 这个数字不是别的,而是9223372036854665216
(称之为U
)。
如果我们将尾数减少一个等级到1.1...0011
,我们得到9223372036854664192
(称之为L
)。
原始数字在L
和U
之间,并且比L
更接近于U
最后,如果你认为这个尾数的截断应该导致一个以一串零结尾的数字,那么你是对的。 只有它以二进制forms出现,而不是十进制:基数为16的U
为0x7ffffffffffe5000
, L
为0x7ffffffffffe4c00
。
因为双打没那么精确。 你为什么这么奇怪? 将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