我需要从二进制文件中读取值,数据格式为IBM单精度浮点数(4字节十六进制指数数据),并将该值用作十进制数字。我有从文件读取并取出每个字节并像这样存储的C ++代码
unsigned char buf[BUF_LEN];
for (long position = 0; position < fileLength; position += BUF_LEN) {
file.read((char* )(&buf[0]), BUF_LEN);
// printf("\n%8ld: ", pos);
for (int byte = 0; byte < BUF_LEN; byte++) {
// printf(" 0x%-2x", buf[byte]);
}
}
这将输出每个字节的十六进制值。
此图片指定IBM单精度浮点IBM single precision floating point我不明白什么是24位正二进制分数。我确实知道如何在十六进制之间进行转换,所以我的基本理解是将所有q都当作一个非常长的二进制段,将Q24(2)^(23)用作最大值,同时将所有前面的值加在一起,然后将数字乘以10 ^ -24即可。但是我的直觉告诉我这是错误的。澄清什么是小数点或MSB会有所帮助。
该格式实际上非常简单,并且与IEEE 754 binary32格式没有特别的区别(它实际上更简单,不支持任何“魔术” NaN / Inf值,并且不具有次正规数,因为此处的尾数为隐式0在左侧,而不是隐式的1)。
正如Wikipedia所说,
该数字表示为以下公式:(-1)符号×0.significand×16 指数-64。
如果我们假设您读取的字节在uint8_t b[4]
中,则结果值应类似于:
uint32_t mantissa = (b[1]<<16) | (b[2]<<8) | b[3];
int exponent = (b[0] & 127) - 64;
double ret = mantissa * exp2(-24 + 4*exponent);
if(b[0] & 128) ret *= -1.;
[注意,这里我在double
中计算了结果,因为IEEE 754 float
的范围不足以表示相同大小的IBM单精度值(也相反)。另外,请记住,由于字节顺序问题,您可能必须还原上述代码中的索引。
编辑:@ Eric Postpischil正确地指出,如果您有C99或POSIX 2001,那么应该使用mantissa * exp2(-24 + 4*exponent)
代替ldexp(mantissa, -24 + 4*exponent)
,它应该更精确(并且可能更快)。 )跨实施。