从浮点小端到大端再转换回来的问题
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()?" 是因为我试图理解并可能简化您的测试程序,而不是期望解决问题。
我正在尝试编写一个保存解析器,它以小端形式保存浮点数,但是,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()?" 是因为我试图理解并可能简化您的测试程序,而不是期望解决问题。