2016-01-02 2 views
2

Я имею дело с упакованным двоичным файлом данных, который я пытаюсь декодировать, модифицировать и перекодировать. Мне нужно иметь возможность переупаковать значения float так же, как они были распакованы. Значение поплавка в этом примере кода -1865.0. Что мне нужно сделать в byte4float так, чтобы возвращаемые четыре байта были такими же, как я начал, то есть (C3 74 90 00).Java IEEE 754 float to IBM float byte [4] conversion

public class HelloWorld { 
    public static void main(String[] args) { 
     byte[] bytes = {(byte) 0xC3,(byte) 0X74,(byte) 0X90,(byte) 0X00 }; 
     byte newbytes[] = new byte[4]; 
     float f; 
     f = float4byte (bytes[0], bytes[1], bytes[2], bytes[3]); 
     System.out.println("VAL Bytes : " + f); 

     // Now see if we can reverse it 
     // NOT Working 
     newbytes = byte4float(f); 
     System.out.println ("TO Bytes: "+String.format("%02X ", newbytes[0])+ 
       String.format("%02X ", newbytes[1])+String.format("%02X ", newbytes[2])+String.format("%02X ", newbytes[3])); 

    } 

    /** 
    * Convert four bytes into a float value. Byte parameters 
    * 
    * @param a highest byte 
    * @param b higher byte 
    * @param c lower byte 
    * @param d lowest byte 
    * 
    * @return float value 
    */ 

    private static float float4byte(byte a, byte b, byte c, byte d) 
    { 

     int sgn, mant, exp; 
     System.out.println ("IN Byte : "+String.format("%02X ", a)+ 
       String.format("%02X ", b)+String.format("%02X ", c)+String.format("%02X ", d)); 

     mant = (b &0xFF) << 16 | (c & 0xFF) << 8 | (d & 0xFF); 
     if (mant == 0) return 0.0f; 

     sgn = -(((a & 128) >> 6) - 1); 
     exp = (a & 127) - 64; 

     return (float) (sgn * Math.pow(16.0, exp - 6) * mant); 
    } 

    /** 
    * Convert float value into a four bytes. 
    * 
    * @param f float value to convert 
    * 
    * @return byte[0] highest byte, byte[1] higher byte, byte[2] lower byte, byte[3] lowest byte 

    */ 

    private static byte[] byte4float(float f) 
    { 
     byte newbytes[] = new byte[4]; 
     int bits = Float.floatToIntBits(f); 

     newbytes[0] = (byte)(bits & 0xff); 
     newbytes[1] = (byte)((bits >> 8) & 0xff); 
     newbytes[2] = (byte)((bits >> 16) & 0xff); 
     newbytes[3] = (byte)((bits >> 24) & 0xff); 

     return newbytes; 
    } 

} 
+0

Следует также упомянуть, что float4byte был скопирован из библиотеки, которая считывает эти файлы, но не записывает их. Я не разработал это решение. –

+2

Начните с понимания того, как сконфигурировано [32-битное значение с плавающей точкой IEEE-754] (https://en.wikipedia.org/wiki/Single-precision_floating-point_format). Затем поймите, как отличаются мантисса, экспоненты и знаки вашего формата. Из быстрого взгляда видно, что у вас есть 24-битная мантисса со всеми явными битами и 7-битный показатель с двумя дополнениями, причем старший бит является значком. – kdgregory

ответ

3

Тот факт, что ваш mantisse 24 бит и экспоненты 7 бит указывает на то, что вы имеете дело с IBM style single precision floating points. У меня возникли проблемы с тем, почему float4byte делает sgn * Math.pow(16.0, exp - 6) * mant, когда я понял, что это просто то же самое, что и sgn * Math.pow(16, exp) * (mant/Math.pow(2, 24), что точно так же работает с поплавками IBM.

Что вы кодируете, являются общими IEEE-754 single precision floating points. Неправильное совпадение вызывает проблемы.

На IBM floating point architecture wikipedia article вы можете найти пример того, как закодировать число с плавающей запятой на байты IBM float.

0

Благодаря вводу @halfbit и некоторым незначительным изменениям эта процедура преобразует float IEEE 754 в float IBM.

public static byte[] byte4float(float f) { 
    assert !Float.isNaN(f); 
    // see also JavaDoc of Float.intBitsToFloat(int) 

    int bits = Float.floatToIntBits(f); 
    int s = (bits >> 31) == 0 ? 1 : -1; 
    int e = (bits >> 23) & 0xFF; 
    int m = (e == 0) ? (bits & 0x7FFFFF) << 1 : (bits& 0x7FFFFF) | 0x800000; 

    int exp = (e - 150)/4 + 6; 
    int mant; 
    int mantissaShift = (e - 150) % 4; // compensate for base 16 
    if (mantissaShift >= 0) mant = m >> mantissaShift; 
    else mant = m >> (Math.abs(mantissaShift)); 
    if (mant > 0xFFFFFFF) { mant >>= 4; exp++; } // loose of precision */ 
    byte a = (byte) ((1 - s) << 6 | (exp + 64)); 
    return new byte[]{ a, (byte) (mant >> 16), (byte) (mant >> 8), (byte) mant }; 
} 

Я думаю, что это правильно и, кажется, работает.

Смежные вопросы