Я пишу программу на Java для ввода файла, который будет использоваться другой программой, написанной на C ++. Как следствие, этот файл должен быть двоичным файлом чисел с обратным порядком байтов с обратным порядком байтов.
Я использовал много разных способов сделать это преобразование порядка байтов, включая Apache Commons I / O, утилиту Geosoft (которая является тем же самым, что и apache ..) и ByteBuffer.
Таким образом, я должен взять кучу чисел с плавающей запятой и отобразить их в двоичном порядке с прямым порядком байтов. Этот процесс работает большую часть времени. Однако в некоторых случаях кажется, что есть некоторая ошибка точности в преобразовании порядка байтов, когда число с плавающей точкой распознается как NaN. В результате вместо определенного числа с плавающей запятой отображается число вроде 6.055E-41 или что-то в этом роде, когда я читаю только что записанный двоичный файл примерно в 1% случаев. Я искал похожие проблемы в Интернете.
Еще один человек диагностировал ошибку, содержащуюся в преобразовании между числами с плавающей запятой в биты Int и битами с плавающей запятой (обнаружено в утилитах Apache и Geosoft).
Рекомендуемое решение заключалось в том, чтобы преобразовать файл непосредственно в биты типа int, а не выполнять этот раундовый процесс. Однако преобразование непосредственно в целые числа в моем случае заставит меня потерять точность исходных чисел с плавающей запятой, которые мне нужно записать. Рекомендуемое решение для вашей справки:
"Путем чтения числа с плавающей запятой с помощью процедуры readFloat () DataInputStream, преобразования его в биты с помощью Float.floatToIntBits (), замены целого числа и последующего преобразования его обратно в число с плавающей запятой с помощью Float.intBitsToFloat () в некоторых случаях приводит к ошибке точности, что приводит к возвращение барахла.
Решение состоит в том, чтобы написать новый набор процедур, которые считывают биты из потока байтов непосредственно в целые числа, а затем выполняют обмен байтов и преобразовывают их обратно в число с плавающей запятой ".
Вот пример проблемы ...
При записи этих серий чисел с плавающей запятой в двоичный файл и чтении их обратно ожидаемый результат будет следующим:
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)));
}
Постановили: Благодаря Луи Вассерману ответ на мои проблемы был найден:
dataOutputStream.writeInt(Integer.reverseBytes(Float.floatToRawIntBits(float))).
Float.floatToIntBits
совершенно не требует точности. Почему вы предполагаете, что это будет? (Я имею в виду, что он объединит разные NaN, но это не должно быть проблемой для вас, и даже если бы это было так, вы могли бы вместо этого использоватьFloat.floatToRawIntBits
.) - person Louis Wasserman   schedule 16.07.2013float
- это 32 бита.int
- это 32 бита.Float.floatToRawIntBits
иFloat.intBitsToFloat
- идеальные противоположности; это должно быть полностью обратимым. У вас есть тест, который более конкретно демонстрирует проблему? - person Louis Wasserman   schedule 16.07.2013intValue = swap(intValue)
? - person Louis Wasserman   schedule 19.07.2013swap
метод? Вы определяетеfloat swap(float value)
, а затем вызываете другой методswap
? И имеет ли смысл возвращать значение с обратным порядком байтов к float, а не сохранять его какint
? - person Louis Wasserman   schedule 19.07.2013int
s, это, вероятно, все равно должно работать, если программа C ++ пытается прочитать их как байты. FWIW, базовый JDK имеет метод для изменения порядка байтовint
:Integer.reverseBytes(int)
. - person Louis Wasserman   schedule 19.07.2013InputStream
, вам нужно просто написать одну строкуFloat.intBitsToFloat(Integer.reverseBytes(dataInputStream.readInt()))
. Если вы пишете их вOutputStream
, вы должны просто написать одну строкуdataOutputStream.writeInt(Integer.reverseBytes(Float.floatToRawIntBits(float)))
. Все остальное просто ходит по кругу. - person Louis Wasserman   schedule 19.07.2013