-2

这是我尝试过的:

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这里实际上是一个不正确的值。PS我对 的了解很差IEEE 754,所以也许我发现的行为是绝对正确的,但4这里显然是错误的值。

4

2 回答 2

7

您需要了解并非每个long都可以精确表示为double- 毕竟,有 256 8 long个值,并且最多有那么多double值(尽管其中很多是为“非数字”值等保留的)。鉴于还有一些 double显然不是long值(例如,0.5 - 任何非整数,首先),这意味着不可能double每个值都有一个long值。

这意味着如果您从一个long无法表示的值开始,将其转换为 a double,然后再转换回 a long,则返回一个不同的数字是完全合理的。

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

于 2013-07-29T18:00:03.413 回答
2

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

Javadouble格式使用 1 位符号和 11 位指数。剩下 52 位来编码有效数(浮点数的小数部分)。

对于普通数字,有效数字有一个前导 1 位,后跟一个二进制点,然后是编码的 52 位。

Long.MAX_VALUE/2, 4611686018427387903, 转换为double时,必须四舍五入以适合这些位。4611686018427387903 是 0x3fffffffffffffff。那里有 62 个有效位(两个无意义的前导零,然后是 62 位)。由于并非所有 62 位都适合可用的 53 位,因此我们必须将它们四舍五入。最后九位,我们必须通过四舍五入消除,是 111111111 2。我们必须将它们四舍五入到零(产生 0x3ffffffffffffffe00)或高达 1000000000 2(进入下一个更高位并产生 0x4000000000000000)。后一个变化(加1)小于前一个变化(减111111111 2)。我们想要一个更小的误差,所以我们选择后者并四舍五入。因此,我们将 0x3fffffffffffffff 舍入到 0x4000000000000000。这是 2 62,即 4611686018427387904。

于 2013-07-29T19:13:49.117 回答