【问题标题】:Sign, mantissa, and exponent of a double双精度数的符号、尾数和指数
【发布时间】:2017-03-08 01:34:38
【问题描述】:

我从How to get the sign, mantissa and exponent of a floating point number找到以下代码

#include <stdio.h>
typedef union {
  float f;
  struct {
    unsigned int mantisa : 23;
    unsigned int exponent : 8;
    unsigned int sign : 1;
  } parts;
} double_cast;

int main() {
  double_cast d1;
  d1.f = 0.15625;
  printf("sign = %x\n",d1.parts.sign);
  printf("exponent = %x\n",d1.parts.exponent);
  printf("mantisa = %x\n",d1.parts.mantisa);
  return 0;
}

但是如何将其转换为尾数为 52、指数为 11、符号为 1 的双精度数?

【问题讨论】:

    标签: c floating-point


    【解决方案1】:

    只需扩展逻辑并像这样定义您的联合,使用标准 int 64 实现可移植性:

    #include <stdint.h>
    
    typedef union {
      double f;
      struct {
        uint64_t mantisa : 52;
        uint64_t exponent : 11;
        uint64_t sign : 1;
      } parts;
    } double_cast;
    

    https://en.wikipedia.org/wiki/Double-precision_floating-point_format

    顺便说一句:浮点映射也应该使用标准类型,而不是int

    typedef union {
      float f;
      struct {
        uint32_t mantisa : 23;
        uint32_t exponent : 8;
        uint32_t sign : 1;
      } parts;
    } float_cast;
    

    【讨论】:

    • 谢谢,很长的声明是什么? 8 个字符的值呢?
    • a long 可以是 8 字节或 4 字节之类的,这就是为什么 &lt;stdint.h&gt; 存在的原因:提供具有定义大小的统一类型。
    • 这不是很便携,因为 C 标准不限制位域的布局方式。
    • @OregonState2016,你的整个方法是不可移植的。您不能依赖联合以您希望发生的方式将位域映射到 float / double 的位。
    • @OregonState2016,是的,实际上。 frexp() 系列函数专门用于分隔浮点数的符号+尾数和指数部分。从那里到达你想去的地方相当简单。不要忽视这样一个事实,即规范化的 IEEE-754 FP 数字在尾数中有一个额外的隐含 1 位,您可能需要考虑这一点。
    【解决方案2】:

    我认为您应该只使用位和移位运算符从双精度/浮点数中提取字段。您可以为此制作宏/功能。

    【讨论】:

    • 位运算符仅适用于整数类型,不适用于floatdouble或其他实数类型。
    • 使用指针访问一种类型的对象,就好像它是不同类型的对象一样会调用未定义的行为。有一些例外,但唯一可以在这里应用的是通过char *unsigned char * 访问实际值。这可能行得通,但它比简单的 shift / mask / done 更复杂。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-14
    • 1970-01-01
    • 2011-02-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-07
    相关资源
    最近更新 更多