简体   繁体   English

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

[英]Why use Double.doubleToLongBits() instead of casting?

EDIT: 编辑:

I think my purpose was not understood, and so the negative votes and comments. 我认为我的目的没有被理解,因此投了反对票和评论。 I am NOT interested in knowing what bit of a floating point(double) means what, and if they match the same position in a long; 我对知道浮点数(双精度数)的含义以及它们是否长时间匹配相同位置不感兴趣; this is totally irrelevant to me. 这与我完全无关。 My problem is the following: I want to use a single primitive array to store all my primitive values. 我的问题如下:我想使用一个原始数组存储所有原始值。 If I choose a double[] as "storage", I need to be able to store longs in it too (I could also do it the other way around, but the problem would not go away, just be reversed). 如果我选择double []作为“存储”,我还需要能够在其中存储多头(我也可以用其他方法来做,但是问题不会消失,只是可以逆转)。 Since both are the same size, it should work, somehow. 由于两者的大小相同,因此应该可以正常工作。 Using Double.doubleToRawLongBits(double) and Double.longBitsToDouble(long) allow me to do that. 使用Double.doubleToRawLongBits(double)和Double.longBitsToDouble(long)可以做到这一点。 But what I wanted to know was: "Can I just put cast a long to an double and back, and always get the same long back?" 但是我想知道的是:“我可以只将一首长乐投向双打并退回,并始终获得相同的长投回吗?” If THAT is true, then it solves my problem, and I don't care if the bits gets moved around internally. 如果那是真的,那么它解决了我的问题,而且我也不在乎这些钻头是否在内部移动。 So I wanted to test if I can safely safely do this. 所以我想测试我是否可以安全地做到这一点。 The output says all 64 bits could be accessed and modified individually, but possibly this is not sufficient to prove that no long bit gets lost/modified. 输出显示所有64位都可以单独访问和修改,但这可能不足以证明没有长位丢失/修改。

I just discovered, with a small test, that I can correctly "address" every bit in a double, just by casting to long and back. 我刚刚进行了一次小测试,发现我可以正确地“寻址”成双倍的每一位,只需将其长短地放回去即可。 Here the test program (which succeeds, at least on Java 7 / Windows 7 64bit): 这里是测试程序(至少在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));
        }
    }
}

Assuming my test program correctly "proves" that every bit of a double can be accessed, just by casting to long and back, why do we have the following native methods: 假设我的测试程序正确地“证明”了可以通过双击long和back来访问double的每一位,为什么我们具有以下本机方法:

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

Since native methods are usually slower (the content of the method might be faster, but the overhead of native call make it slower), is there any benefit to using those methods? 由于本机方法通常较慢(方法的内容可能较快,但是本机调用的开销使其变慢),因此使用这些方法有什么好处?

The bit pattern of a floating point number will NEVER (with ONE exception) remotely resemble the bit pattern of the corresponding integer value, if one exists. 如果存在浮点数的位模式,则永远不会(除非一个例外)与相应整数值的位模式相似。

I suggest you run the following program 我建议您运行以下程序

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);
    }
}

Then read What Every Computer Scientist Should Know About Floating-Point Arithmetic 然后阅读每位计算机科学家应该了解的有关浮点运算的知识

(The exception is, of course, the value zero) (当然,例外是零值)

If you want to investigate further, there's a neat interactive floating point converter at CUNY that displays everything you'd ever want to know about any given number's float representations. 如果您想进一步研究,CUNY有一个简洁的交互式浮点转换器 ,其中显示了您想要了解的任何给定数字的浮点表示形式的所有信息。

This is the test I should have used. 这是我应该使用的测试。 It fails at 53, which (I assume) means that only the first 52 bits of a long could be stored in a double "safely" without using those native methods (this also precludes using any negative values). 它在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));
    }
}

The problem with my original test was that I tested the bits individually . 我原来测试的问题是,我单独测试的位。 By always setting the first bit to 1, I can find out when I start loosing data , because the least significant bit is the "first to go". 通过始终将第一位设置为1,我可以找出何时开始丢失数据 ,因为最低有效位是“第一位”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM