Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

小数与浮点数

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

复习

  1. 第三章:了解了二进制,以及怎样用位权展开一个数

TL;DR

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

正文

二进制里的小数

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

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

  • 0.12 = 1/2 = 0.510
  • 0.012 = 1/4 = 0.2510
  • 0.112 = 1/2 + 1/4 = 0.7510

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

定点数

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

  • 比如约定“高 8 位是整数部分,低 8 位是小数部分“

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

浮点数:用科学计数法

  科学家记很大的数或很小的数时,会用科学计数法,比如:

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。

  这不是计算机算错了,而是“用有限位表示无限小数“的必然结果。所以,涉及钱、精确数值时,程序员通常改用整数或专门的十进制类型,而不是浮点数。

思考题

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

小结

知识点

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

参考资料

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

思考题答案(仅供参考)

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

协议

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

封面图

设计师 | 南国微雪