Reputation: 38
I am writing a program in Java to input a file to be used by an other program written in C++. In consequence, this file must be a little endian binary file of floats.
I have used many different types of ways to make this endian conversion including Apache Commons I/O, the Geosoft utility (which is the exact same thing as apache..), and ByteBuffer.
In summary, I must take a bunch of floats and display them in binary little endian. This process works most of the time. However, in certain cases, there seems to be some precision error in the endian conversion where a float is recognized as NaN. As a result, instead of the specific float, a number like 6.055E-41 or something is displayed when I read the binary file that I have just written about 1% of the time. I have searched for similar problems online.
One other person had diagnosed the error to be contained within the conversion between float to Int Bits and Int Bits to float (found in the Apache and Geosoft Utilities).
The recommended solution was to make the file directly into int bits rather than doing this round about process. However, converting directly into integers, in my case, would make me lose precision on the original floats that I need to write. The recommended solution was, for your reference:
"By reading a float using the readFloat() routine of DataInputStream, converting it to bits using Float.floatToIntBits(), swapping the Integer, then converting it back to float using Float.intBitsToFloat() causes a precision error in certain cases resulting in junk being returned.
The solution is to write a new set of routines that read the bits from the bytestream directly into integers, then perform the byte swapping and converting it back to a float."
Here is an example of the problem...
When writing these series of floats into a binary file and reading them back, the result expected is this:
1.50411975 -1.974895 1.0301249 -0.43540177 0.8161005 0.38000694 0.43332508
However, I am seeing this:
6.9055E-41 -1.974895 1.0301249 -0.43540177 0.8161005 0.38000694 0.43332508
I am pasting my code. This version specifically uses a byte buffer implementation. Can you please tell me what is wrong and how I can go about fixing it?
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();
}
Here is the alternate swapping mechanism I have:
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;
}
I tried using something that directly uses integers. Here is my special swapper:
public static float specialswap (float value)
{
int intValue = Float.floatToRawIntBits (value);
return Integer.reverseBytes(Integer.parseInt(Integer.toBinaryString(intValue)));
Resolved: Thanks to Louis Wasserman, the answer to my problems was found:
dataOutputStream.writeInt(Integer.reverseBytes(Float.floatToRawIntBits(float))).
Upvotes: 1
Views: 1907
Reputation: 198023
Are you getting numbers from the input stream, or writing them to an output stream? It's still not clear what you're trying to do. If you're reading them from an InputStream
, you should just be doing the one line Float.intBitsToFloat(Integer.reverseBytes(dataInputStream.readInt()))
. If you're writing them to an OutputStream
, you should just be doing the one line dataOutputStream.writeInt(Integer.reverseBytes(Float.floatToRawIntBits(float)))
. Everything else is just going around in circles.
Upvotes: 4