⚙️ 第三章 计算机在计算小数时会出错的原因
📄 一句话概括

浮点数是二进制的科学计数法:符号位+指数位+尾数位,指数让小数点能浮动——名字就是这么来的。

📝 本节和前面几节的关系

3.3 说清了误差的来源,这一节看承载它的那个结构:浮点数。

一、先认识科学计数法

小学学的科学计数法是 1.25 × 10³——把有效数字和小数点位置分开写。 这么做的好处是:同一个格式既能表示很大的数,也能表示很小的数。 浮点数换了底数,写成 1.xxxx × 2ⁿ。 于是那三个部分——正负、有效数字、小数点位置——正好对应三个字段。

二、三个字段

符号位:1 位,决定正负。 指数位:单精度 8 位、双精度 11 位,决定这个数有多大。 尾数位:单精度 23 位、双精度 52 位,决定这个数有多细。 加起来:单精度 1+8+23 = 32 位;双精度 1+11+52 = 64 位。 注意尾数位远多于指数位——说明设计时更看重【精细】而不是【极端范围】。

三、小数点为什么会【浮】

整数的小数点位置是固定的(就在最右边),所以叫定点数。 浮点数的小数点位置由指数决定——指数变,小数点就跟着挪,所以叫【浮】。 这就带来两条独立的轴:指数管范围,尾数管精度。 所以浮点数能同时表示 1e-38 和 1e38,但这两头的精度都只有那 23 位。

四、为什么有效数字只有 7 位左右

23 位尾数换成十进制,大约相当于 7 位有效数字;双精度 52 位约相当于 16 位。 所以别指望双精度算出【小数点后 20 位都正确】的结果——真值里就没有那么多位。 这条常识直接决定了很多实践:比较两个浮点数是否相等,本来就该带容差。 而【容差取多大】,就取决于你用单精度还是双精度——这是下一节要补的最后一块。

五、动手 Demo:浮点数就是二进制的科学计数法

小学学的科学计数法是 1.25 × 10³。浮点数换了底数:1.xxxx × 2ⁿ。

for name, total, s, e, m in (("float", 32, 1, 8, 23),
                             ("double", 64, 1, 11, 52)):
    print("%s: 共 %d 位 = 符号 %d + 指数 %d + 尾数 %d"
          % (name, total, s, e, m))

实跑输出:

--------------------------------------------------------------------
浮点数就是二进制的科学计数法
--------------------------------------------------------------------

小学学的科学计数法是 1.25 × 10³。浮点数换了底数:**1.xxxx × 2ⁿ**。

  类型              总位数     符号位     指数位     尾数位     十进制有效位
  ---------------------------------------------------------------------------
  单精度 float      32         1          8          23         约 7 位
  双精度 double     64         1          11         52         约 16 位

  三个字段各管一件事:
    符号位   0 还是 1,决定正负
    指数位   小数点落在哪儿,决定这个数有多大
    尾数位   有效数字本身,决定这个数有多细

  **指数让小数点【浮动】——这就是【浮点数】这个名字的来历。**
  也正因为小数点浮着,同一个 32 位既能表示 1e-38 也能表示 1e38,
  代价是**有效数字只有那 23 位,超出的部分一律舍弃**。

符号位管正负、指数位管大小、尾数位管精细——三段各司其职。 指数让小数点浮动,这就是【浮点数】这个名字的来历。

30 秒实验

  1. 查一下你常用语言的 float 是多少位、有效数字大约几位。
  2. 试试打印 0.1 + 0.2 和 1/3,观察它们各自能显示到第几位。

常见误区

  1. 以为浮点数只是【带小数点的数】。它是三段结构,小数点位置由指数决定。
  2. 以为 double 一定够用。52 位尾数约 16 位有效数字,超出的部分本来就不存在。
自测三问(点开对答案) 1. 浮点数由哪三个部分组成? —— 符号位、指数位、尾数位。 2. 单精度和双精度各占多少位? —— 单精度 1+8+23=32 位;双精度 1+11+52=64 位。 3. 指数位和尾数位各决定什么? —— 指数位决定能表示多大/多小的范围,尾数位决定有效数字的精细程度。

相关笔记