【问题标题】:Issues with converting from floating point little-endian to big-endian and back again从浮点小端转换到大端并再次转换回来的问题
【发布时间】:2019-04-22 16:25:51
【问题描述】:

我正在尝试编写一个保存解析器,它将浮点数保存为小端,但是,Java 是大端的,所以我需要在写入时转换 FP 并再次返回,但这确实会导致一些浮点数不一致点数。

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

并将浮点数反向转换为原始 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() 的用途。

【问题讨论】:

  • Java 既不是大端也不是小端。这取决于硬件。你看过ByteBuffer吗?它有一个方法来设置缓冲区的字节序(以及你放入其中的所有数据)。
  • 这是一个使用ByteBuffer的例子,如果有帮助请告诉我们:stackoverflow.com/questions/54542268/…
  • @markspace 它确实有效,但是,在大多数情况下,它会使读取文件所需的时间增加一倍甚至三倍(取决于所述文件中的浮点数)(我正在重用相同的字节缓冲区,不是每次都创建一个新的)
  • 你为什么用Float.floatToRawIntBits(raf.readFloat())而不是raf.readInt()
  • @markspace Java 在任何平台上都是大端的。请参阅 RandomAccessFileData/Input/OutputStream 的 Javadoc。

标签: java floating-point endianness


【解决方案1】:

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

IEEE 754 允许其每个单独的 NaN 值具有多个不同的 NaN 值 和双浮点格式。而每个硬件架构 当生成新的 NaN 时,返回 NaN 的特定位模式, 程序员还可以创建具有不同位模式的 NaN 编码,例如,回顾性诊断信息。

在大多数情况下,Java SE 平台处理给定的 NaN 值 键入就好像折叠成单个规范值一样,因此 规范通常指的是一个任意的 NaN,就好像一个 规范值。

我问“为什么你使用 Float.floatToRawIntBits(raf.readFloat()) 而不是 raf.readInt()?”因为我试图理解并可能简化您的测试程序,而不是期望解决问题。

【讨论】:

    猜你喜欢
    • 2011-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-19
    • 2013-10-17
    相关资源
    最近更新 更多