对于经验丰富的程序员来说,这可能是一个基本问题。我有点笨,解决不了这个问题。我正在尝试解压缩一个二进制文件,但doco不太清楚如何存储浮点值。我已经找到了一个可以做到这一点的例程,但只有当我传递一个字节的整数数组时,它才会起作用。正确答案是-1860.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);
}
}
使用ByteBuffer的解决方案不起作用的原因是:字节与浮点值的(Java)内部表示不匹配。
Java表示是
System.out.println(Integer.toHexString(Float.floatToIntBits(-1865.0f)));
这使得CCD_ 1
byte
s是用Java签名的。在计算尾数mant
时,字节从byte
s隐式转换为int
s,符号为"extended",即(byte)0x90
(十进制-112)得到转换后的0xFFFFFF90
(32位int)。然而,您想要的只是原始字节的8位(0x00000090
)。
为了补偿符号扩展的影响,只需更改一行即可:
mant = (b & 0xFF) << 16 | (c & 0xFF) << 8 | (d & 0xFF)
这里,在(c & 0xFF)
中,由符号扩展引起的1比特在(隐式)转换为c4e92000
0之后被剥离。
编辑:
浮动的重新封装可以通过IEEE 754表示来完成,该表示可以通过Float.floatToIntBits
获得(避免使用慢对数)。代码中的一些复杂性是由基数从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 };
}
该代码不考虑可能存在的用于封装的任何规则,例如用于表示零或尾数的归一化。但这可能是一个起点。
由于@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 };
}
我认为这是正确的,而且似乎正在发挥作用。