在C++(gcc)中,浮点数和双精度数是如何表示的?

5

浮点数是如何由编译器表示和解释的。我试图理解这一点,以便能够轻松地解释字节数组对于浮点数和双精度数的含义。

谢谢

3个回答

14

3
我想补充一点,这通常是绝大多数情况,但硬件也会影响选择。 - Don Wakefield

3

值得注意的是,std::numeric_limits 有一个 static bool const 成员变量 is_iec559,仅适用于浮点类型。名称已经很明确了...


2
自解释,只要您知道IEC 559是ISO对IEEE 754的重新规范的名称即可。而且您还应该知道可能会有错误的负面影响:该标准不仅仅是一种表示方式 - 实际上,我不确定1985年版本是否强制规定了一种表示方式 - 还包括行为(舍入、非规格化数等)。将该成员设置为true意味着您遵守所有这些规定并且适用于某些平台。据我所知,Java的第一个版本就强制执行了它,然后又撤回了,因为性能损失太大。 - AProgrammer

1

要真正解释它,您可能不想将其视为字节,因为尾数边界不与8位边界对齐。

大致如下:

mantisa =  (*(unsigned int *)&floatVal) | MANTISA_MASK;
exp     = ((*(unsigned int *)&floatVal) | EXP_MASK    ) >> EXP_SHIFT;
sign    = ((*(unsigned int *)&floatVal) | SIGN_MASK   ) >> SIGN_SHIFT;

会让你拆开来玩弄果汁中心。

编辑:

    #include <stdio.h>

    void main()
    {
    float a = 4;
    unsigned int exp,sign,mantisa;
    int i;

        for(i = 0;i<4;i++)
        {
            exp      = (*((unsigned int *)&a) >>23) & 0xFF;
            sign     = (*((unsigned int *)&a) >>31) & 0x01;
            mantisa  = (*((unsigned int *)&a)) & 0x7FFFFF | 0x800000;

            printf("a       = %04x\r\n",*((unsigned int *)&a));
            printf("a       = %f\r\n",a);
            printf("exp     = %i, %02x\r\n",exp,exp);
            printf("sign    = %i, %02x\r\n",sign,sign);
            printf("mantisa = %i, %02x\r\n\r\n",mantisa,mantisa);
            a = -a / 2;

      }
    }

生成:

    a       = 40800000
    a       = 4.000000
    exp     = 129, 81
    sign    = 0, 00
    mantisa = 8388608, 800000

    a       = c0000000
    a       = -2.000000
    exp     = 128, 80
    sign    = 1, 01
    mantisa = 8388608, 800000

    a       = 3f800000
    a       = 1.000000
    exp     = 127, 7f
    sign    = 0, 00
    mantisa = 8388608, 800000

    a       = bf000000
    a       = -0.500000
    exp     = 126, 7e
    sign    = 1, 01
    mantisa = 8388608, 800000

    Press any key to continue . . .

是的,但这是未定义的行为(使用int指针访问浮点值)。您可以保证能够将对象的字节作为无符号字符数组访问(至少在C中 - 我不确定C ++标准中的相应措辞),但通常无法访问其他数据类型。特别是,编译器的优化器有权假定您没有执行此操作,并应用可能会破坏您代码的优化。 - dewtell
1
此外,在将floatVal强制转换为另一种指针类型之前,您需要先获取其地址。关于优化器的说法,例如:如果编译器在寄存器中保存了floatVal的当前值,则优化器可以认为在执行此代码之前不需要将当前值溢出到内存中,因为int指针不能合法地访问float值。因此,即使未定义的行为没有导致计算机爆炸,使用此代码时也可能轻松地捡起随机垃圾而不是floatVal的最新值。 - dewtell
语言规范与架构无关,因此无法定义浮点数的位定义。例如 TI 在旧型 DSP 上有它自己的浮点格式。如果您指定 IEEE 格式,则正在定义浮点数的位定义。 - NoMoreZealots
未定义行为的其中一种允许实现方式是“正常工作”(即执行程序员期望的操作)而不发出任何警告。也可以随意选择不起作用。编译器通常不会刻意破坏您的代码,但它也没有义务花费任何精力来确保在增加优化级别、添加其他无关更改到代码、升级到新的编译器版本、移植到新平台或在另一个星期二编译时仍然能够正常工作。 - dewtell
& 是被定义好的。返回一个变量的地址。(uint32 ) 也是被定义好的。取一个给定的地址,并将该地址处的值视为 uint32。 也是被定义好的。解引用一个指针。所有东西都由系统架构定义。在使用 C 的 18 年中,我从未见过这种情况失败,包括 gcc 在内的超过半打编译器,在超过半打操作系统和不同的架构上(包括许多没有操作系统的系统)。 - NoMoreZealots
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接