2016-01-01 39 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 }; 
} 

我认为这是正确的,似乎是工作。

相关问题