Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

小数与浮点数

复习

  • 计算机的数据表示:计算机用二进制表示数据,八进制和十六进制是二进制的简写
  • 数据的大小与单位:认识了 bit、Byte 及更大的数据单位,知道 1024 与 1000 的差异
  • 文字与编码:文字靠字符编码表示,ASCII、Unicode 和 UTF-8 解决了编号与存储等系列问题

本章为进阶内容,零基础读者可以跳过,不影响后续阅读。

TL;DR

  • 小数点右边也遵循“逢二进一”,只是位权变成了 1/2、1/4、1/8……
  • 小数点位置固定不动的叫定点数,简单但范围小
  • 浮点数用“科学计数法”的思想:符号 + 阶码 + 尾数,范围大但精度有限
  • 很多十进制小数(比如 0.1)在二进制里是无限循环的,只能近似存储

正文

二进制里的小数

  前面我们表示的都是整数。小数点右边怎么办?

  回忆一下位权:十进制里,0.1 表示 1/10,0.01 表示 1/100。二进制也一样,只是底数换成 2:

  • 0.1₂ = 1/2 = 0.5₁₀
  • 0.01₂ = 1/4 = 0.25₁₀
  • 0.11₂ = 1/2 + 1/4 = 0.75₁₀

  所以二进制小数同样可以“按位权相加”来还原。

定点数

  最简单的小数表示方法,叫 定点数:约定小数点固定在某个位置,小数点前后各占多少位直接定死。

  • 比如约定“高 8 位是整数部分,低 8 位是小数部分”
    • 00000001.00000000 就表示 1.0
    • 00000000.10000000 就表示 0.5
    • 00000000.01000000 就表示 0.25。

  它简单、快,但缺点非常非常明显:能表示的范围和精度都很有限。想要更大范围,就得多给整数位;想要更精细,就得多给小数位,而总位数是固定的,两边打架。

浮点数:用科学计数法

  科学家记很大的数或很小的数时,会用科学计数法,比如:1.23 × 10^5

  它把“数值”拆成三部分:正负号、有效数字(1.23)、指数(5)。这样既能记下 1.23 × 10^5,也能记 1.23 × 10^-5,范围一下大了很多。

  计算机借用了这个思路,做成 浮点数:小数点不再固定,而是“浮动”的。

  • 符号位:正还是负
  • 阶码:相当于指数,决定小数点的位置
  • 尾数:相当于有效数字,决定精度

  现代计算机普遍遵循 IEEE 754 标准来分配这几位。具体位数分配属于细节,这里不展开,只要记住“符号 + 阶码 + 尾数”这个结构即可。

精度问题

  浮点数换来大范围,代价是精度

  一个让人抓狂的例子:在大多数编程语言里,

0.1 + 0.2 == 0.3   // 结果是 false!在编程语言里两者不相等!

  0.1 在二进制里是 无限循环小数(就像十进制的 1/3 = 0.333… 永远写不完)。计算机只能用有限的位去近似它,两个近似值相加,结果就差了那么一点点,不等于精确的 0.3。这里还有个笑话,说以后机器人像人一样有了智能,他们就会问对方 0.1 + 0.2 等于多少,如果对方说是 0.3,那么就是人类,如果说是 0.300000004,那就是机器人。

  这是“用有限位表示无限小数”的必然结果。 所以,涉及钱、精确数值时,程序员通常改用整数或专门的十进制类型,而不是浮点数。 这件事在会计上特别有发言权,会计经典抓狂场景:算了半天,差 0.01 平不了账。这种时候总不能跟人家说:你的账务其实没错,这是计算机表示的原因。以后谁知道是计算机表示的问题,还是真的差了 0.01 呢?

思考题

  十进制里,1/3 = 0.333… 写不完,所以只能近似。请类比说明:为什么 0.1 在二进制里也“写不完”?这和浮点数算不准有什么关系?

小结

知识点

  • 二进制小数与位权
  • 定点数及其局限
  • 浮点数:符号 + 阶码 + 尾数
  • IEEE 754
  • 浮点数的精度问题

参考资料

  1. Wikipedia(zh):浮点数:浮点数的基本概念
  2. Wikipedia(zh):IEEE 754:浮点数标准

思考题答案(仅供参考)

  十进制里分母含 3 的分数写不完,是因为 10 的因子是 2 和 5,除不尽。同理,二进制只认因子 2,而 0.1₁₀ = 1/10 的分母含着因子 5,用二进制除不尽,所以是无限循环小数。计算机只能用有限多位去截断、近似它,于是 0.1、0.2 都不是精确值,相加自然就凑不出精确的 0.3。其根本在于进制和分母“对不上”。

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪