我正在用Java编写一个程序来输入一个由C ++编写的其他程序使用的文件。因此,此文件必须是浮点数的小端二进制文件。
我使用了许多不同类型的方法来进行这种端点转换,包括Apache Commons I / O,Geosoft实用程序(与apache完全相同)和ByteBuffer。
总之,我必须拿一堆浮点数并以二进制小端显示它们。这个过程大部分时间都有效。但是,在某些情况下,在endian转换中似乎存在一些精度错误,其中float被识别为NaN。结果,当我读取我刚刚写过的大约1%的二进制文件时,显示的是6.055E-41之类的数字,而不是特定的浮点数。我在网上搜索过类似的问题。
另一个人已经诊断出错误包含在float到Int Bits和Int Bits之间的转换中浮动(在Apache和Geosoft Utilities中找到)。
推荐的解决方案是将文件直接转换为int位而不是围绕进程执行此操作。但是,在我的情况下,直接转换为整数会让我失去我需要编写的原始浮点数的精度。推荐的解决方案是供您参考:
“通过使用DataInputStream的readFloat()例程读取float,使用Float.floatToIntBits()将其转换为位,交换Integer,然后使用Float.intBitsToFloat()将其转换回float,导致某些精度错误导致垃圾返回的案件。
解决方案是编写一组新的例程,将字节流中的位直接读入整数,然后执行字节交换并将其转换回浮点数。“
以下是问题的一个例子......
将这些系列的浮点数写入二进制文件并将其读回时,预期的结果如下:
1.50411975 -1.974895 1.0301249 -0.43540177 0.8161005 0.38000694 0.43332508
但是,我看到了这一点:
6.9055E-41 -1.974895 1.0301249 -0.43540177 0.8161005 0.38000694 0.43332508
我正在粘贴我的代码。此版本专门使用字节缓冲区实现。你能告诉我出了什么问题以及如何解决它吗?
public int writeBinaryFile( ArrayList<P> p) throws FileNotFoundException, IOException
{
int c = 0;
for (int i = 0; i < p(); i++)
{
ArrayList<Float> cube = new ArrayList<Float>();
ArrayList<Float> dir = p.get(i).getDirection();
ArrayList<Float> pos = p.get(i).getPosition();
Float angle = (float) p.get(i).getAngle();
Float id = (float) p.get(i).getPEvents().get(0).getid();
ArrayList<Float> things = new ArrayList<Float>();
boolean truism = true;
if (dir.get(1) > 0 ) {
/*byte [] byte2 = this.float2ByteArray(id);
float f = ByteBuffer.wrap(byte2).order(ByteOrder.LITTLE_ENDIAN ).getFloat();
dos.writeFloat(f);*/
for (int j = 0; j < pos.size(); j++) {
byte [] bytes = this.float2ByteArray(pos.get(j));
float d = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN ).getFloat();
cube.add(d);
}
for (int j = 0; j < dir.size(); j++) {
byte [] bytes = this.float2ByteArray(dir.get(j));
float d = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN ).getFloat();
cube.add(d);
}
byte [] bytes = this.float2ByteArray(angle);
float d = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN ).getFloat();
cube.add(d);
if (this.checkCube(cube)) {this.writeCube(cube); c++; }
}
}
return c;
}
public byte [] float2ByteArray(float value)
{
return ByteBuffer.allocate(4).putFloat(value).array();
}
这是我的备用交换机制:
public static float swap (float value)
{
int intValue = Float.floatToRawIntBits (value);
intValue = swap (intValue);
return Float.intBitsToFloat (intValue);
}
public static int swap (int value)
{
int b1 = (value >> 0) & 0xff;
int b2 = (value >> 8) & 0xff;
int b3 = (value >> 16) & 0xff;
int b4 = (value >> 24) & 0xff;
return b1 << 24 | b2 << 16 | b3 << 8 | b4 << 0;
}
我尝试使用直接使用整数的东西。这是我的特别交换器:
public static float specialswap (float value)
{
int intValue = Float.floatToRawIntBits (value);
return Integer.reverseBytes(Integer.parseInt(Integer.toBinaryString(intValue)));
解决:感谢Louis Wasserman,我找到了问题的答案:
dataOutputStream.writeInt(Integer.reverseBytes(Float.floatToRawIntBits(float))).
答案 0 :(得分:4)
您是从输入流中获取数字,还是将它们写入输出流?目前还不清楚你要做什么。如果您是从InputStream
阅读,那么您应该只进行一行Float.intBitsToFloat(Integer.reverseBytes(dataInputStream.readInt()))
。如果您将它们写入OutputStream
,则应该只执行一行dataOutputStream.writeInt(Integer.reverseBytes(Float.floatToRawIntBits(float)))
。其他一切都只是围成一圈。