2016-01-01 41 views
1

這可能是一個更有經驗的程序員的基本問題。我是一個小白,不能工作這一個。我試圖解開一個二進制文件,並且doco對於如何存儲浮動內容不太清楚。我找到了一個這樣做的例程,但只有當我傳遞一個字節的整數數組時纔會起作用。正確答案是-1865.0。我需要能夠傳遞字節數組並獲得正確的答案。我如何需要更改代碼以使float4byte返回-1865.0。提前致謝。將字節[4]轉換爲浮點數 - 整型[4]數組可以工作,但字節[4]不會

import java.nio.ByteBuffer; 
import java.nio.ByteOrder; 

public class HelloWorld { 
    public static void main(String[] args) { 
     byte[] bytes = {(byte) 0xC3,(byte) 0X74,(byte) 0X90,(byte) 0X00 }; 
     int[] ints = {(int) 0xC3,(int) 0X74,(int) 0X90,(int) 0X00 }; 

     // This give the wrong answer 
     float f = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getFloat(); 
     System.out.println("VAL ByteBuffer BI: " + f); 

     // This give the wrong answer 
     f = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getFloat(); 
     System.out.println("VAL ByteBuffer LI: " + f); 

     //This gives the RIGHT answer 
     f = float4int (ints[0], ints[1], ints[2], ints[3]); 
     System.out.println("VAL Integer : " + f); 

     // This gives the wrong answer 
     f = float4byte (bytes[0], bytes[1], bytes[2], bytes[3]); 
     System.out.println("VAL Bytes : " + f); 

    } 
    private static float float4int(int a, int b, int c, int d) 
    { 

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

     mant = b << 16 | c << 8 | d; 
     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); 
    } 

    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 << 16 | c << 8 | d; 
     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); 
    } 

} 

回答

1

byte s是用Java簽名的。當計算尾數mant時,字節被隱含地從byte s轉換爲ints - 帶有符號「擴展」,即(byte)0x90(十進制-112)被轉換爲0xFFFFFF90(32位int)。然而,你想要的只是原始字節的8位(0x00000090)。

爲了補償符號擴展的效果,只要改變一個行:

mant = (b & 0xFF) << 16 | (c & 0xFF) << 8 | (d & 0xFF) 

在此,在(c & 0xFF),由符號擴展的1比特被後(隱含的)轉換爲剝離int


編輯:

浮子的重新包裝可經由其可以通過Float.floatToIntBits獲得(這避免了使用對數慢)的IEEE 754表示來完成。有的在代碼複雜度由鹼的變化引起的從2至16:

private 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 << (mantissaShift + 4); exp--; } 
    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 }; 
} 

代碼不考慮可能存在的包裝的任何規則,例如用於表示尾數的零或歸一化。但它可能是一個起點。

+0

此解決方案完美運作。問題解決了。謝謝。我將需要扭轉過程並以相同的方式重新打包浮動。不知道我知道如何。任何提示如何做到這一點也不勝感激。 –

+0

@Andrew L:爲反向函數'byte4float'添加了一個示例實現。請參閱編輯。 – halfbit

+0

謝謝@halfbit。我發現的是,我正在使用舊的IBM 370大型機float。請參閱[IBM_Floating_Point_Architecture](https://en.wikipedia.org/wiki/IBM_Floating_Point_Architecture#IEEE_754_on_IBM_mainframes)。這個解決方案並不完善,但還有一些工作要做。 –

2

ByteBuffer解決方案無法正常工作的原因:字節與float值的(Java)內部表示形式不匹配。

Java表示

System.out.println(Integer.toHexString(Float.floatToIntBits(-1865.0f))); 

這給c4e92000

+0

+1,儘管嚴格來說,這不一定是真的,那就是「(Java)內部表示」。'Float.floatToIntBits'被指定使用IEEE 754單精度(binary32)表示,而Java實現只需要爲它們的'float'-s使用相同的值(不一定是每個值的相同表示)。 – ruakh

0

由於@halfbit和位測試和細微的變化,這個例程出現轉換IEEE 754浮點數到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 }; 
} 

我認爲這是正確的,似乎是工作。

相關問題