Java 将字节[4]转换为浮点整数[4]数组有效,但字节[4]无效

Java 将字节[4]转换为浮点整数[4]数组有效,但字节[4]无效,java,floating-point,Java,Floating Point,对于那些经验丰富的程序员来说,这可能是一个基本问题。我有点糊涂,不能解决这个问题。我正在尝试解包一个二进制文件,而doco对浮点数的存储方式不太清楚。我已经找到了一个这样做的例程,但它只有在我传递一个整数字节数组时才能工作。正确答案是-1865.0。我需要能够传递字节数组并得到正确答案。我需要如何更改代码以使float4byte返回-1865.0。提前谢谢 import java.nio.ByteBuffer; import java.nio.ByteOrder; public class H

对于那些经验丰富的程序员来说,这可能是一个基本问题。我有点糊涂,不能解决这个问题。我正在尝试解包一个二进制文件,而doco对浮点数的存储方式不太清楚。我已经找到了一个这样做的例程,但它只有在我传递一个整数字节数组时才能工作。正确答案是-1865.0。我需要能够传递字节数组并得到正确答案。我需要如何更改代码以使float4byte返回-1865.0。提前谢谢

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);
    }

}
导入java.nio.ByteBuffer;
导入java.nio.ByteOrder;
公共类HelloWorld{
公共静态void main(字符串[]args){
字节[]字节={(字节)0xC3,(字节)0X74,(字节)0X90,(字节)0X00};
int[]int={(int)0xC3,(int)0X74,(int)0X90,(int)0X00};
//这给出了错误的答案
float f=ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getFloat();
System.out.println(“VAL ByteBuffer BI:+f”);
//这给出了错误的答案
f=ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getFloat();
System.out.println(“VAL ByteBuffer LI:+f”);
//这是正确的答案
f=float4int(整数[0],整数[1],整数[2],整数[3]);
System.out.println(“VAL整数:+f”);
//这给出了错误的答案
f=float4byte(字节[0],字节[1],字节[2],字节[3]);
System.out.println(“VAL字节:+f”);
}
私有静态浮点float4int(inta、intb、intc、intd)
{
国际邮资、邮资、出口;
System.out.println(“IN Int:+String.format(“%02X”,a))+
String.format(“%02X”,b)+String.format(“%02X”,c)+String.format(“%02X”,d));
mant=b6)-1);
exp=(a&127)-64;
返回(浮动)(sgn*数学功率(16.0,exp-6)*mant);
}
专用静态浮点4字节(字节a、字节b、字节c、字节d)
{
国际标准、螳螂、经验;
System.out.println(“字节:“+String.format”(%02X),a)+
String.format(“%02X”,b)+String.format(“%02X”,c)+String.format(“%02X”,d));
mant=b6)-1);
exp=(a&127)-64;
返回(浮动)(sgn*数学功率(16.0,exp-6)*mant);
}
}

字节
是用Java签名的。当计算尾数
mant
时,字节从
byte
s隐式转换为
int
s,符号为“extended”,即
(byte)0x90
(decimal-112)转换为
0xffff90
(32位int)。但是,您需要的只是原始字节的8位(
0x00000090

为了补偿符号扩展的影响,只需更改一行即可:

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

代码未考虑包装可能存在的任何规则,例如表示尾数为零或标准化的规则。但这可能是一个起点。

使用ByteBuffer的解决方案不起作用的原因是:字节与浮点值的(Java)内部表示形式不匹配

Java表示是

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

它提供了
c4e92000

多亏了@halbit和一些测试和微小的更改,该例程将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 };
}
公共静态字节[]字节4float(float f){
assert!Float.isNaN(f);
//另请参见Float.intBitsToFloat(int)的JavaDoc
整数位=浮点。浮点到整数位(f);
int s=(位>>31)==0-1:-1;
int e=(位>>23)&0xFF;
int m=(e==0)?(位&0x7FFFFF)=0)尾数=m>>尾数为ft;
else mant=m>>(Math.abs(mantissaShift));
如果(mant>0xFFFFFFF){mant>>=4;exp++;}//精度不高*/
字节a=(字节)(字节)(1-s)>16),(字节)(mant>>8),(字节)mant};
}

我认为这是正确的,而且似乎很有效。

这个解决方案非常有效。问题解决了。谢谢我将需要反转这个过程,并以同样的方式重新打包浮动。我不知道该怎么做。任何关于如何实现的提示都将不胜感激。@Andrew L:添加了反向函数
byte4float
的示例实现。请参阅编辑。谢谢@halbit。我发现我使用的是旧的IBM370大型机float。看见这个解决方案不太管用,但需要做一些工作。+1,虽然严格来说,这不一定是“Java内部表示”
Float.floatToIntBits
指定使用IEEE 754单精度(binary32)表示,而Java实现只需要为其
Float
-s使用相同的值集(不一定是每个值的相同表示)。
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 };
}