编辑:
我认为我的目的没有被理解,所以负面的投票和评论。我不想知道什么位浮点(双)意味着什么,以及它们是否匹配长的相同位置;这跟我完全无关。我的问题如下:我想使用单个基本数组来存储我所有的原始值。如果我选择双[]作为“存储”,我需要能够存储多头(我也可以反过来做,但问题不会消失,只是反过来)。因为两者都是相同的大小,它应该工作,不知何故。使用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)
由于本机方法通常较慢(方法的内容可能更快,但本机调用的开销使其变慢),使用这些方法有什么好处吗?
答案 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,我可以找到何时开始丢失数据,因为最低有效位是“首先去”。