从浮点小端到大端再转换回来的问题

Issues with converting from floating point little-endian to big-endian and back again

我正在尝试编写一个保存解析器,它以小端形式保存浮点数,但是,Java 是大端形式,所以我需要在写入时将 FP 转换回来,但这确实如此导致某些浮点数不一致。

我试过读取浮点数,转换为 int 位,反转 int 位,然后再转换回浮点数。

然后将 float 反向转换为原始 int 位,反转 int 位,然后再转换回浮点数。


    public void test()
    {
        //file contents (hex) 0x85, 0x76, 0x7e, 0xbd, 0x7f, 0xd8, 0xa8, 0x3e, 0x2f, 0xcb, 0x8f, 0x3d, 0x06, 0x7c, 0x70, 0x3f
        RandomAccessFile iRAF = new RandomAccessFile(new File("input.test"), "r");
        RandomAccessFile oRAF = new RandomAccessFile(new File("output.test"), "rw");

        byte[] input = new byte[16];
        iRAF.readFully(input);

        float[] floats = new float[4];
        for (int i = 0; i < 4; i++)
        {
            floats[i] = readFloat(iRAF);
        }
        writeFloats(oRAF, floats);

        byte[] output = new byte[16];
        oRAF.seek(0);
        oRAF.readFully(output);

        if (Arrays.equals(input, output) == false)
        {
            System.err.println(toHex(input));
            System.err.println(toHex(output));
        }
    }

    private String toHex(byte[] bytes)
    {
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++)
        {
            sb.append(String.format("%02x", bytes[i])).append(" ");
        }
        return sb.toString();
    }

    public float readFloat(RandomAccessFile raf) throws IOException
    {
        return Float.intBitsToFloat(Integer.reverseBytes(Float.floatToRawIntBits(raf.readFloat())));
    }

    public void writeFloats(RandomAccessFile raf, float... floats) throws IOException
    {
        for (int i = 0; i < floats.length; i++)
            raf.writeFloat(Float.intBitsToFloat(Integer.reverseBytes(Float.floatToRawIntBits(floats[i]))));
    }

我希望输出与输入具有完全相同的十六进制值:

85 76 7e bd 7f d8 a8 3e 2f cb 8f 3d 06 7c 70 3f

但实际输出是:

85 76 7e bd 7f c0 00 00 2f cb 8f 3d 06 7c 70 3f

这是由于某些浮点舍入错误造成的,或者可能是在将其转换为 NaN 值而不保留这些位时(尽管我认为这就是 Float.floatToRawIntBits() 的用途。

我相信您遇到了 NaN 崩溃的问题。如果你真的需要区分不同的 NaN 值,你将遇到比文件存储更多的问题。根据 Java 语言规范,4.2.3. Floating-Point Types, Formats, and Values:

IEEE 754 allows multiple distinct NaN values for each of its single and double floating-point formats. While each hardware architecture returns a particular bit pattern for NaN when a new NaN is generated, a programmer can also create NaNs with different bit patterns to encode, for example, retrospective diagnostic information.

For the most part, the Java SE Platform treats NaN values of a given type as though collapsed into a single canonical value, and hence this specification normally refers to an arbitrary NaN as though to a canonical value.

我问 "Why do you use Float.floatToRawIntBits(raf.readFloat()) rather than raf.readInt()?" 是因为我试图理解并可能简化您的测试程序,而不是期望解决问题。