我试图用IEEE754双精度在float64中实现从十六进制到C++的转换。这是我第一次玩比特,所以我的代码可能不够干净。我不知道为什么我的尾数给了我奇怪的结果,但我想我做错了什么。
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有人知道怎么做吗?
谢谢
发布于 2017-08-08 12:24:11
长int raw =0x40000F00000001;
实现指定了long是否足够长以容纳那么多位(通常在Windows上不是,在Linux上是这样,如果您编译64位程序,而不是32位)。
int符号=原始>> 63;
如果设置了符号位,则这一行具有实现定义的行为。(看似合理的结果是1和-1,但没有什么可以阻止指定“42”的实现。)将raw定义为uint64_t要好得多。
长整数尾数= (raw &0xFFFFFFFFFFFF);尾数+=1;
这是你的问题。缺失的“1”位位于所有位元的前面。相反,您需要添加0x10000000000(或者更好地定义一个常量const uint64_t MantissaOffset = 1uLL << 52;和另一个const uint64_t MantissaMask = MantissaOffset-1; -这样您就不必计算所有的Fs和0s)。
然后,尾数是2**52,太大了(所以在计算指数时需要考虑这个问题。)
双exp =((原始>> 52) & 0x7FF) - 1023;双结果= pow(-1.,符号)*尾数* pow(2.0,exp);
..。当然,这并不能解释非正常人,NANs和INFs。
cout <<“尾数:”<<尾数“<<”EXP:“<< exp << endl;cout <<”结果:“<<结果<< endl;
发布于 2017-08-08 12:16:44
我觉得你的尾数差不多没问题了。对于0x40000F0000000001分数是0xF0000000001 (至少52位),它正好是16492674416641。老实说,我不知道你为什么要加一个。
如果你想要一个很好的例子,你可以使用它,你可以看到这维基百科页面。在一章的末尾,有一个非常好的例子,说明如何从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位值时,使用uint64_t类型更安全,它保证64位大小。您可以通过包含<stdint.h>头来使用它。
https://stackoverflow.com/questions/45567479
复制相似问题