我需要读取二进制文件中的值,数据格式是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位正二进制分数是什么.我知道如何在十六进制< - > dec< - >二进制之间进行转换,所以我的基本理解是将所有的q作为一个非常长的二进制段,它将使用Q24(2)^(23)作为将所有前面的值加在一起时的最大值,然后将数字乘以10 ^ -24.但我的直觉告诉我这是错的.我也不知道基数点或MSB是什么.
关于如何使用这些数据的任何想法?我的目标是使用每个值作为新点绘制线条.
我知道这不是很简短,但这不是一个简短的问题不能简洁的话题.
解决方法:
格式实际上非常简单,并没有特别不同于IEEE 754 binary32格式(它实际上更简单,不支持任何“神奇的”NaN / Inf值,并且没有次正规数,因为这里的尾数有一个隐含的0离开而不是隐含1).
正如Wikipedia所说,
The number is represented as the following formula: (−1)sign × 0.significand × 16exponent−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单精度值(也相反).另外,请记住,由于endian问题,您可能必须在上面的代码中还原索引.
编辑:@Eric Postpischil正确地指出,如果你有C99或POSIX 2001可用,而不是尾数* exp2(-24 4 *指数)你应该使用ldexp(尾数,-24 4 *指数),这应该更精确(并且可能更快)跨实现.