我正在尝试编写一个保存解析器,它以小端保存浮点数,但是,Java是big-endian,所以我需要在写入时再转换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 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为其单浮点格式和双浮点格式提供了多个不同的NaN值。虽然每个硬件架构在生成新的NaN时返回NaN的特定位模式,但是程序员也可以创建具有不同位模式的NaN以编码例如回顾性诊断信息。
在大多数情况下,Java SE平台将给定类型的NaN值视为折叠为单个规范值,因此该规范通常将任意NaN称为规范值。
我问“为什么你使用Float.floatToRawIntBits(raf.readFloat())而不是raf.readInt()?”因为我试图理解并可能简化你的测试程序,而不是期望解决问题。