不是科班生,不会知道计算机中的「小数点」问题!

将程序视点设为星标精品文章第一时间阅读

大家好,欢迎来到程序视点!我是小二哥。

上一篇文章中,我们解释了计算机的底层只能处理小数的基础逻辑。今天我们继续。

前情回顾

回顾下,定点数的含义。约定计算机中小数点的位置,且这个位置固定不变,小数点前、后的数字,分别用二进制表示,然后组合起来就可以把这个数字在计算机中存储起来,这种表示方式叫做「定点」表示法,用这种方法表示的数字叫做「定点数」

也就是说「定」是指固定的意思,「点」是指小数点,小数点位置固定即定点数名字的由来。

定点数表示方法

前面,我们说过,任何一个数,我们都可以看成这样格式:

整数部分 + 小数部分

那必然就有这三种情况:

纯整数

例如整数100,小数点其实在最后一位,所以忽略不写

如果我们以 1 个字节(8 bit)表示,用定点数表示如下(D为十进制缩写,B为二进制缩写):

代码语言:javascript
复制
100(D) = 01100100(B)

这种情况用定点数表示都比较简单,按照十进制转为二进制规则,即可得到结果。

纯小数

例如:0.125,小数点固定在最高位

同样以 1 个字节(8 bit)表示,用定点数表示如下:

代码语言:javascript
复制
0.125(D) = 0.00100000(B)
// 这里的小数点是虚拟的。主要为了方便大家看

这种情况用定点数表示都比较简单,按照十进制转为二进制规则,即可得到结果。ps:不清楚纯小数转换为二进制的小伙伴,可以查询这篇文章

整数+小数

这种情况下,我们需要先约定小数点的位置。因为是定点数表示法嘛,那就是要固定小数点的位数。

假如以 1 个字节(8 bit)为例,那我们可以约定前 5 位表示整数部分,后 3 位表示小数部分。对于数字 1.5 用定点数表示时,先处理整数1,那5 bit表示是这样的:

代码语言:javascript
复制
1(D) = 00001

接着是小数上的0.5,用3 bit表示是这样的:

代码语言:javascript
复制
0.5(D) = 0.100(B)

再把两个部分合起来,结果是这样:

代码语言:javascript
复制
1.5(D) = 00001 100(B)

这里总结一下用定点数表示一个小数的过程:

  • 在有限的 bit 宽度下,先约定小数点的位置
  • 整数部分和小数部分,分别转换为二进制表示
  • 两部分二进制组合起来,即是结果

又如数字 25.125 用定点数表示就是这样:

代码语言:javascript
复制
25.125(D) = 11001 001(B)

范围和精度问题

刚才我们约定了前 5 位表示整数部分,后 3 位表示小数部分。此时,这个整数部分的二进制最大值只能是 11111,即十进制的 31;小数部分的二进制最大只能表示 0.111,即十进制的 0.875。显然,用后 3 位 bit 位表示小数部分,是不能把小数涵盖完的。

如果我们想要表示更大范围的值,怎么办?

1.扩大 bit 的宽度:例如使用 2 个字节、4 个字节,这样整数部分和小数部分宽度增加,表示范围也就变大了。

2.改变小数点的位置:小数点向后移动,整个数字范围就会扩大,但是小数部分的精度就会越来越低,没有办法表示类似 0.00001 这种高精度的值。

但不管如何约定小数点的位置,我们都会发现这种表示方式存在以下问题:

数值的表示范围有限(小数点越靠左,整个数值范围越小) 数值的精度范围有限(小数点越靠右,数值精度越低)

总的来说,定点数表示小数就是范围有限,精度低。要想解决这 2 个问题,计算机科学家们提出了使用「浮点数」的方式表示数字。关于「浮点数」,我们下期接着讲。