2013-07-29 27 views
-2

这里是我的尝试:转换龙在java中翻一番,我发现了一些差异

public class LongToDoubleTest{ 
    public static void main(String... args) { 
     System.out.println(Long.MAX_VALUE); 
     System.out.println(Long.MAX_VALUE/2); 
     System.out.println(Math.floor(Long.MAX_VALUE/2)); 
     System.out.println(new Double(Math.floor(Long.MAX_VALUE/2)).longValue()); 
    } 
} 

这里是输出:

9223372036854775807 
4611686018427387903 
4.6116860184273879E18 
4611686018427387904 

我最初是想弄清楚,是否有可能保持Long.MAX_VALUE的一半不丢失数据,所以我对除了最后一行以外的所有行进行了测试。所以看起来我是对的,最后3失踪了。然后,为了澄清它,我添加了最后一行。而不是3出现,但4。所以我的问题是,从那里出现4以及为什么它是4而不是3。因为4这里实际上是一个不正确的值。 P.S.我对IEEE 754的知识知之甚少,所以也许我发现的行为是绝对正确的,但4在这里显然是错误的值。

+0

4.6116860184273879 ** E18 ** –

回答

6

你要明白,不是每个long可以精确地表示为double - 毕竟,有256个 long值,并最多许多double值(虽然很多的那些被保留用于“不是数字“值等)。假设存在double值明显不是long值(例如0.5-任何非整数,用于开始),这意味着每个long值不可能有double值。

,如果您使用的是不能代表一个long值开始,将其转换为double,然后回long表示,这是完全合理的得到一个不同的数字。

相邻double值之间的绝对差值随着数值的幅度变大而增加。所以当数字非常小时,两个数字之间的差异确实很小(确实非常小) - 但是当数字变大时 - 例如,高于int的范围 - 数字之间的差距变大......甚至大于1.因此,相邻的double值接近Long.MAX_VALUE的距离可能相当远。这意味着几个long值将映射到最近的double

+0

所以'4'我最终得到了绝对无法预测?它可能具有相同的概率“9”或“7”? – dhblah

+0

@dhblah:好吧不 - 对于任何给定的'long',都会有一个它应该四舍五入的“double”。如果您查看所涉及的确切位模式,这是可以预测的 - 但肉眼难以预测。 –

+0

我的意思是,'4'并不意味着四舍五入出错了,这仅仅是因为位模式? – dhblah

0

这里的算术是完全可预测的。

Java double格式使用一位用于符号,十一位用于指数。这留下52位来编码有效位数(浮点数的小数部分)。

对于正常数字,有效位数有一个前导1位,后面跟着一个二进制点,后面跟着52位编码。

Long.MAX_VALUE/2,4611686018427387903转换为double时,它必须舍入以适应这些位。 4611686018427387903是0x3fffffffffffffff。这里有62个有效位(两个前导零不重要,然后是62位)。由于并不是所有的62位都适用于53位,所以我们必须将它们四舍五入。最后九位,我们必须舍去,这是111111111 。我们必须将它们舍入到零(产生0x3ffffffffffffe00)或高达1000000000 (它携带到下一个更高位并产生0x4000000000000000)。后面的变化(加1)小于以前的变化(减去111111111 )。我们想要一个更小的错误,所以我们选择后者并凑合。因此,我们将0x3fffffffffffffff舍入到0x4000000000000000。这是2 ,这是4611686018427387904.

+1

哦,很好的解释。如果只有我能理解它。 – dhblah