跳至正文
View Categories

< 1 min read

主要内容 #

本节,我们主要来探讨:小数在内存中是怎么表示的。

首先,和整数直接存储的方式不同。
小数是无法直接存储的,原因在于,整数有“单位一”,可以表示为多少个“一”。
然后,在内存中,可以相当于往柜子中放东西一样,将这个整数“逐一”放在内存空间中。

很显然,小数做不到这一点。

1. 科学计数法 #

在数学中,我们学习过:小数,一般也可以使用科学计数法来表示。

314159.26 = 3.1415926*10^5

使用科学计数法,一个小数可以用这样几个“整数”来表示。

314159.26 = 3.1415926*10^5

符号位    整数部分    小数部分    指数
0         3         1415926    5

类似的,由于我们在内存中的所有数值其实是二进制,
所以,我们需要先来了解“二进制中的科学计数法”

2. 二进制的科学计数法 #

先来计算 0.6 的二进制。

第一步 0.6*2=1.2  取1,得到 0.1
第二步 0.2*2=0.4  取0,得到 0.10
第三步 0.4*2=0.8  取0,得到 0.100
第四步 0.8*2=1.6  取1,得到 0.1001
第五步 0.6*2=1.2  取1,得到 0.10011
... 从第五步开始循环

所以最终结果为:0.100110011001...



写作科学计数法:1.001100110011...*10^(-1)



符号位    整数部分    小数部分(保留一定的位数)    指数
0         1         001100110011               -1



二进制中,科学技术法的整数部分都是取 1 ,所以可以省略。最终结果为:

符号位    小数部分(保留一定的位数)    指数
0        001100110011               -1
  • 一个十进制下的有限小数,可能在二进制下是一个无限循环小数。
  • 这是小数无法完整表示的原因之一。
  • 所以,以 float 为例,小数在内存中的表示规则为:

  • 第 1 位是符号位,1 表示负数,0表示非负数
  • 第 2~9 位(共8位),是“指数”,也称为“阶码”
  • “指数”,把真值+127
  • 第 10~32 位(共23位),是“小数部分”,也称为“尾数”
  • “小数部分”,近似方法:用0舍1
  • 符号位    小数部分(保留一定的位数)    指数
    0        001100110011               -1
    
    -1 加上127,得到 126:0111 1110
    
    float 占 4 字节,32 位
    0  |011 1111 0|001 1001 1001 1001 1001 1001
    +- | 指数 | 小数部分
    
    
    对应的十六进制为:0x3f19999a

    3. 实验 #

    请运行如下的代码,验证 0.6 的内存分布。

    #include < iostream >
    using namespace std;
    int main()
    {
        float dashima = 0.6f;
        int* pa = (int*)(&dashima);    // 转成等长度的整形,必须使用指针的强制类型转化
        cout << setbase(16) << "0x"<< (*pa) << endl; // 3fc00000
    
        return 0;
    }

    4. 小结 #

  • 浮点数在内存中是无法精确表示的
  •            符号位   阶码   尾数     总长度
    float        1      8     23       32
    double       1      11    52       64

    习题 #

    课后练习