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

小数点右边也有位权,依次是 1/2、1/4、1/8、1/16……;分母是 2 的幂就能精确写,否则写不完。

📝 本节和前面几节的关系

3.1 摆出了问题,这一节回答第一问:二进制到底怎么表示小数,0.1 又卡在哪儿。

一、小数点右边也有位权

整数部分从右往左是 1、2、4、8……小数点右边反过来:1/2、1/4、1/8、1/16…… 一样是 2 的幂,只是指数变成负的。 所以 0.101(二)= 1/2 + 0 + 1/8 = 0.625。 写法上和十进制是一模一样的逻辑:看哪些位是 1,把它们的位权加起来。

二、哪些小数能精确表示

判据很干脆:看分母是不是 2 的幂。 分母是 2 的幂 → 一位一位凑得上,能精确写:0.5、0.25、0.125、0.75、0.8125。 分母里混了别的质因数 → 写不完:0.1、0.2、0.3、0.7。 原因在十进制那边看得很清楚:0.1 = 1/10 = 1/2 ÷ 5,而 5 不是 2 的幂。

三、0.1 的二进制长什么样

0.1 的二进制展开是 0.0001100110011001100110011…——【0011】四位数无限循环。 这就像十进制里的 1/3 = 0.3333…,永远写不完。 计算机只有有限位(单精度 23 位、双精度 52 位),只能写到某一位然后停手。 停手的方式(截断或舍入)就是 3.3 要讲的误差来源。

四、换算的方法

十进制小数 → 二进制:不断乘 2,把每次的整数部分取出来。 例:0.625 × 2 = 1.25 取 1;0.25 × 2 = 0.5 取 0;0.5 × 2 = 1.0 取 1 —— 得 0.101。 这就是为什么 0.1 写不完:乘 2 的过程会一直循环下去,永远到不了 0。 整数的换算是【除 2 取余】,小数的换算是【乘 2 取整】——方向相反,别记混。

五、动手 Demo:二进制怎么表示小数

二进制小数点的右边,位权依次是 1/2、1/4、1/8、1/16…… 和整数那边一样是 2 的幂,只是指数变成了负的。

for v, parts in ((0.5, "1/2"), (0.25, "1/4"), (0.125, "1/8")):
    print("%s = %s" % (v, parts))
# 0.1 的二进制展开:
x, out = 0.1, ""
for _ in range(12):
    x *= 2
    out += str(int(x))
    x -= int(x)
print("0.1 -> 0." + out + "...(0011 循环下去)")

实跑输出:

--------------------------------------------------------------------
二进制怎么表示小数
--------------------------------------------------------------------

**二进制小数点的右边,位权依次是 1/2、1/4、1/8、1/16……**
和整数那边一样是 2 的幂,只是指数变成了负的。

  十进制     它由哪些位权拼成     二进制写法
  -------------------------------------------
  0.5        1/2                  0.1
  0.25       1/4                  0.01
  0.125      1/8                  0.001
  0.75       1/2 + 1/4            0.11
  0.625      1/2 + 1/8            0.101
  0.8125     1/2 + 1/4 + 1/16     0.1101

  规律:**只要分母是 2 的幂,就能用有限位精确写出来。**
  可 0.1 的分母是 10,拆开是 1/2 ÷ 5——**5 不是 2 的幂,除不尽。**

  十进制     二进制展开                        能用有限位表示吗
  --------------------------------------------------------------
  0.5        0.1                               能,一位就够
  0.25       0.01                              能
  0.1        0.0001100110011…(0011 循环)     不能,只能截断
  0.2        0.0011001100110…(0011 循环)     不能,只能截断

  **0.1 在二进制里是个无限循环小数——这就是所有麻烦的源头。**

分母是 2 的幂就能精确写;0.1 的分母是 10,拆开含因数 5,二进制里除不尽。 0.1 在二进制里是无限循环小数——这是整章所有麻烦的源头。

30 秒实验

  1. 在纸上用【乘 2 取整】把 0.6875 换成二进制。
  2. 试着把 0.3 换成二进制,看它从第几位开始循环。

常见误区

  1. 以为小数位权是 1/10、1/100。二进制只有 2 的幂,没有【十分之一】这一档。
  2. 以为是【精度不够】所以取个近似。是【根本写不完】——再多位也写不完。
自测三问(点开对答案) 1. 二进制小数点右边的位权是什么? —— 1/2、1/4、1/8、1/16……也就是 2 的负次幂。 2. 什么样的十进制小数能用二进制精确表示? —— 分母是 2 的幂的(0.5、0.25、0.125 等)。 3. 0.1 为什么写不完? —— 0.1 = 1/10,因数里有 5,而 5 不是 2 的幂,二进制展开是无限循环。

相关笔记