No.
2023-06-24
  • Jan
  • Feb
  • Mar
  • Apr
  • May
  • Jun
  • Jul
  • Aug
  • Sep
  • Oct
  • Nov
  • Dec
  • Sun
  • Mon
  • Tue
  • Wed
  • Thu
  • Fri
  • Sat
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

浮点数在内存中的存储

计算机中只能存储二进制数,对于浮点数,IEEE754 标准中定义了在计算机中如何存储浮点数。标准中定义了四种表示浮点数类型的方式,分为单精度(32比特)、双精度(64比特),拓展单精度(43比特以上,很少使用)和拓展双精度(79比特以上,通常用 80 比特表示)。我们以单精度浮点数为例来介绍浮点数的存储。

浮点数存储

浮点数表示

一个浮点数可以表示为:

\[Value = sign \times exponent \times fraction\]

即:

\[\pm fraction * 2^{exponent}\]

浮点数在存储时也按这种表示法被分为三部分,符号部分(sign),指数部分(exponent)和尾数部分(fraction)。

单精度浮点数中符号位占 1 位,指数部分占 8 位,尾数部分占后 23 位:

floatInMemory.png

双精度浮点数中符号位占 1 位,指数部分占 11 位,尾数部分占后 52 位:

doubleInMemory.png

拓展双精度浮点数中符号位占 1 位,指数部分占 15 位,尾数部分占后 64 位:

各部分详解

  1. 符号位:0 表示正值,1 表示负值。
  2. 指数位:指数位在存储时为了保证无符号,会使用移码来表示,即在指数值上添加一个偏移量,这个偏移值是固定的,为 $ 2^{n - 1} - 1 $,n 为指数位的位数。如单精度偏移值为 $ 2^{8-1} - 1=127 $,双精度偏移值为 $ 2^{11 - 1} - 1=1023 $。
  3. 尾数位:每个浮点数最后都会转化为尾数在[1,2)之间,如 20.5 转化为浮点数表示为 1.01001 * 2 ^ 4。因为尾数都在[1,2)之间,所以会省略小数点前的 1,只存储小数点后的位。不够位数后面补 0。

浮点数存储示例

现在我们用一个示例来看浮点数是怎么存储的,比如 -13.375,因为是负值,因此符号位为 1,然后我们将除去符号位的部分 13.375 转为二进制为:1101.011,此值表示为指数形式为 1.101011 * 2^3,指数部分为 3,将其加上偏移量 3+127=130,指数部分为 130,二进制为 1000 0010,尾数部分将 1.101011 舍去小数点前的位数,并在其后添加 0 到 23 位后值为 1010 1100 0000 0000 0000 000。因此 -13.375 在内存中存储为:

1100 0001 0101 0110 0000 0000 0000 0000

验证代码:

// 小端打印二进制
void print_binary4(char* ptr)
{
    for (int i = 3; i >= 0; i--) {
        for (int j = 0; j < 8; j++) {
            printf("%1u", (ptr[i] >> (7-j) & 0x01));
            if (j == 3)
                printf(" ");
        }
        printf(" ");
    }
    printf("\n");
}

int main(int argc, char* argv[])
{
    float f = -13.375;
    printf("f:%f binary:\n", f);
    print_binary4((char*)(&f));
    
    return 0;
}

打印结果为:

binaryResult.png

非规约数

我们之前看的都是规约数(normal number),还有一种百规约数(subnormal number),有四种形式:

  1. 指数为 0,且尾数部分为 0,表示 0。
  2. 指数为 0,且尾数部分为 0,表示非常接近于 0 的数。
  3. 指数为 2 ^ (n-1) (即全1),尾数部分为 0,表示正负无穷大(infinity)。
  4. 指数为 2 ^ (n-1) (即全1),尾数部分不为 0,表示NaN(not a number)。

参考
IEEE754详解(最详细简单有趣味的介绍)
百度百科-IEEE 754