为什么使用Double.doubleToLongBits()而不是强制转换?

时间:2014-02-09 23:20:55

标签: java

编辑:

我认为我的目的没有被理解,所以负面的投票和评论。我不想知道什么位浮点(双)意味着什么,以及它们是否匹配长的相同位置;这跟我完全无关。我的问题如下:我想使用单个基本数组来存储我所有的原始值。如果我选择双[]作为“存储”,我需要能够存储多头(我也可以反过来做,但问题不会消失,只是反过来)。因为两者都是相同的大小,它应该工作,不知何故。使用Double.doubleToRawLongBits(double)和Double.longBitsToDouble(long)允许我这样做。但我想知道的是:“我可以把长时间的投射放到一个双重和背部,并且总是得到相同的长背?”如果这是真的,那么它解决了我的问题,我不在乎这些位是否在内部移动。所以我想测试一下我是否能安全地做到这一点。输出表示可以单独访问和修改所有64位,但这可能不足以证明没有长位丢失/修改。

我刚刚通过一个小测试发现,我可以正确地“解决”双重中的每一点,只需通过长时间和后退。这里是测试程序(成功,至少在Java 7 / Windows 7 64bit上):

import static org.junit.Assert.assertTrue;
import org.junit.Test;

public class TestDoubleBits {
    private static double set(final double d, final int bit, final boolean value) {
        if (value) {
            return ((long) d) | (1L << bit);
        } else {
            return ((long) d) & ~(1L << bit);
        }
    }

    private static boolean get(final double d, final int bit) {
        return (((long) d) & (1L << bit)) != 0;
    }

    @Test
    public void testDoubleBits() {
        final double value = Math.random();
        for (int bit = 0; bit < 64; bit++) {
            assertTrue((get(set(value, bit, false), bit) == false));
            assertTrue((get(set(value, bit, true), bit) == true));
        }
    }
}

假设我的测试程序正确“证明”可以访问double的每一位,只需通过强制转换为long和back,为什么我们有以下 native 方法:

Double.doubleToRawLongBits(double)
Double.longBitsToDouble(long)

由于本机方法通常较慢(方法的内容可能更快,但本机调用的开销使其变慢),使用这些方法有什么好处吗?

2 个答案:

答案 0 :(得分:5)

浮点数的位模式永远不会(有一个例外)远程类似于相应整数值的位模式(如果存在)。

我建议你运行以下程序

public class Test
{
    public static void main(String[] args) {
        double d = 1.3;
        long d1 = (long) d;
        long d2 = (Double.doubleToLongBits(d));
        System.out.printf("cast %016X bits %016X\n", d1, d2);
    }
}

然后阅读What Every Computer Scientist Should Know About Floating-Point Arithmetic

(当然,例外是零值)

如果你想进一步调查,在CUNY有一个整洁的互动floating point converter,显示你想知道的关于任何给定数字的浮动表示的所有内容。

答案 1 :(得分:0)

这是我应该使用的测试。它在53处失败,(我假设)意味着只有一个long的前52位可以“安全地”存储在双精度中而不使用那些原生方法(这也排除了使用任何负值)。

public class TestDoubleBits {
    public static void main(final String[] args) {
        int failsAt = -1;
        long value = 1;
        for (int bit = 1; bit < 64; bit++) {
            value = value | (1L << bit);
            final double d = value;
            final long l2 = (long) d;
            if (value != l2) {
                failsAt = bit;
                break;
            }
        }
        System.out.println("failsAt: " + failsAt);
        value = value & ~(1L << failsAt);
        System.out.println("Max value decimal: " + value);
        System.out.println("Max value hex:     " + Long.toHexString(value));
        System.out.println("Max value binary:  " + Long.toBinaryString(value));
    }
}

我原来测试的问题是我单独测试了。通过始终将第一位设置为1,我可以找到何时开始丢失数据,因为最低有效位是“首先去”。