我知道有精确错误的怪异东西,但我无法理解,
(long)9223372036854665200d
为什么要给我9223372036854665216
?
答案 0 :(得分:34)
9223372036854665200d
是double
类型的常量。但是,9223372036854665200
不适合double
而不会损失精度。 double
只有52位尾数,而有问题的数字需要63位才能准确表示。
最接近的double
到9223372036854665200d
是尾数等于1.1111111111111111111111111111111111111111111110010100
的二进制数,其指数为63(十进制)。这个数字不是9223372036854665216
(称之为U
)。
如果我们将尾数减少一个等级到1.1...0011
,我们得到9223372036854664192
(称之为L
)。
原始数字介于L
和U
之间,距U
更接近L
最后,如果你认为这个尾数的截断应该导致一个以一串零结尾的数字,那么你是对的。只有它以二进制形式发生,而不是十进制:基数为16的U
为0x7ffffffffffe5000
而L
为0x7ffffffffffe4c00
。
答案 1 :(得分:16)
因为双打没那么精确。你为什么这么奇怪?将d更改为l。
答案 2 :(得分:6)
Doubles
具有52-53位精度,而long
具有64位精度(仅适用于整数)。 double中的精度损失用于表示指数,这允许double
表示比long
更大/更小的数字。
您的号码长度为19位,而双倍号码只能存储大约16位数的(十进制)整数数据。因此,最终的数字最终会被舍入。
答案 3 :(得分:5)
因为双打有限precision。你的常数有一个比双重记录更多的有效数字,所以它会丢失它们。
答案 4 :(得分:3)
您假设有限精度意味着它以十进制表示,因此限制为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