十六进制到浮点数 IEEE 754 双精度 c++

Hexadecimal to float IEEE 754 double precision c++

本文关键字:双精度 c++ IEEE 浮点数 十六进制      更新时间:2023-10-16

我正在尝试以 IEEE 754 双精度在 C++ 中从十六进制转换为 float64。 这是我第一次玩比特,所以也许我的代码不够干净。 我不知道为什么我的尾数给了我奇怪的结果,但我认为我做错了什么。

long int raw = 0x40000F0000000001;
int sign = raw >> 63;
long int mantissa = (raw & 0xFFFFFFFFFFFFF);
mantissa +=1;
double exp = ((raw >> 52) & 0x7FF) - 1023;
double result = pow(-1., sign) * mantissa * pow(2.0, exp);
cout << "MANTISSA: " << mantissa << " EXP: " << exp << endl;
cout << "RESULT: " << result << endl;

输出为:

MANTISSA: 16492674416642 EXP: 1
RESULT: 3.29853e+13

有人知道怎么做吗?

谢谢

long int raw = 0x40000F0000000001;

它指定了long是否足够长以容纳那么多位(通常在Windows上不是,在Linux上是如果你编译一个64位的程序,而不是32位。

int sign = raw >> 63;

如果设置了符号位,则此行具有实现定义的行为。 (合理的结果是 1 和 -1,但没有什么可以阻止指定"42"的实现。 您将raw定义为uint64_t会更好

long int mantissa = (raw & 0xFFFFFFFFFFFFF);
mantissa +=1;

这是你的问题。 缺少的"1"位位于所有位的前面。 您需要添加0x1000000000000(或者更好的是,定义一个常量const uint64_t MantissaOffset = 1uLL << 52;和另一个const uint64_t MantissaMask = MantissaOffset-1;- 这样您就不必计算所有这些F0s。

然后,您将拥有一个太大 2**52 的尾数(因此在计算指数时需要考虑这一点。

double exp = ((raw >> 52) & 0x7FF) - 1023;
double result = pow(-1., sign) * mantissa * pow(2.0, exp);

......当然,这并不能解释非正态、NAN 和 INF。

cout << "MANTISSA: " << mantissa << " EXP: " << exp << endl;
cout << "RESULT: " << result << endl;

在我看来,你的尾数几乎没问题。对于0x40000F0000000001分数是0xF0000000001(至少 52 位(,正好是16492674416641.老实说,我不知道你为什么要加 1。

如果你想要一个很好的例子,你可以看看这个维基百科页面。在一章的末尾,有一个非常好的例子,说明如何逐步从它的 64 位原始表示中获取双精度:

Given the hexadecimal representation 3FD5 5555 5555 5555(16),
Sign = 0
Exponent = 3FD(16) = 1021
Exponent Bias = 1023 (constant value; see above)
Fraction = 5 5555 5555 5555(16)
Value = 2^(Exponent - Exponent Bias) × 1.Fraction – Note that Fraction must not be converted to decimal here
= 2^-2 × (15 5555 5555 5555(16) × 2^-52)
= 2^-54 × 15 5555 5555 5555(16)
= 0.333333333333333314829616256247390992939472198486328125
˜ 1/3

另外,请注意:当您处理 64 位值时,使用保证为 64 位大小uint64_t类型更安全。您可以通过包含<stdint.h>标头来使用它。