【问题标题】:Hexadecimal to float IEEE 754 double precision c++十六进制浮点 IEEE 754 双精度 C++
【发布时间】:2017-08-08 11:45:35
【问题描述】:

我正在尝试使用 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

有人知道怎么做吗?

谢谢

【问题讨论】:

    标签: c++ hex


    【解决方案1】:
    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”位位于所有位的 front。您需要添加 0x1000000000000(或者更好的是,定义一个常量 const uint64_t MantissaOffset = 1uLL &lt;&lt; 52; 和另一个 const uint64_t MantissaMask = MantissaOffset-1; - 这样您就不必计算所有这些 Fs 和 0s。)

    然后你会得到一个 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;
    

    【讨论】:

      【解决方案2】:

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

      如果您想要一个如何使用它的好例子,您可以查看this wikipedia 页面。在一章的最后有一个很好的例子,说明如何一步一步地从它的 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 类型会更安全。您可以通过包含&lt;stdint.h&gt; 标头来使用它。

      【讨论】:

      • 他添加了“1”,因为您的示例代码显示1.Fraction。并且提取了很多 5,然后使用 15... - 这是他试图添加的前导 1。
      • @MartinBonner 好吧,那绝对不是+=1,正如您在回答中已经提到的那样。
      猜你喜欢
      • 2011-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-19
      • 2013-07-24
      • 1970-01-01
      • 1970-01-01
      • 2021-04-23
      相关资源
      最近更新 更多