IBM单精度浮点数据转换为预期值

问题描述 投票:1回答:1

我需要从二进制文件中读取值,数据格式为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会有所帮助。

c++ byte bit
1个回答
4
投票

该格式实际上非常简单,并且与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),它应该更精确(并且可能更快)。 )跨实施。

© www.soinside.com 2019 - 2024. All rights reserved.