一、浮点数的不精确性
1、引子
我们开发一个电商App商品的价格常常会是 9 块 9;
现在流行的深度学习算法,对应的机器学习里的模型里的各个权重也都是 1.23 这样的数。
可以说,在实际的应用过程中,这些有零有整的实数,是和整数同样常用的数据类型,我们也需要考虑到。
2、不是0.9而是 0.8999999999999999
1、Linux 下打开 Python 的命令行 Console
2、在 Chrome 浏览器里面通过开发者工具,打开浏览器里的
出来的结果居然不是准确的 0.9,而是 0.8999999999999999 这么个结果。这是为什么呢?
32个比特,能够表示所有的实数吗?
答案很显然是不能。
1、32 个比特,只能表示 2 的 32 次方个不同的数,差不多是 40 亿个。如果表示的数要超过这个数,就会有两个不同的数的二进制表示是一样的。
那计算机可就会一筹莫展,不知道这个数到底是多少。
2、40 亿个数看似已经很多了,但是比起无限多的实数集合却只是沧沧海一粟。所以,这个时候,计算机的设计者们,就要面临一个问题:
我到底应该让这 40 亿个数映射到实数集合上的哪些数,在实际应用中才能最划得来呢?
二、定点数的表示
1、BCD 编码表示
2、BCD 编码的用用场景
3、BCD 编码缺点
三、浮点数的表示
如果我们想在一张便签纸上,用一行来写一个十进制数,能够写下多大范围的数?
1、宽度限制了我们能够表示的数的大小
因为我们要让人能够看清楚,所以字最小也有一个限制。你会发现一个和上面我们用 BCD 编码表示数一样的问题,
是纸张的宽度限制了我们能够表示的数的大小。如果宽度只放得下8 个数字,那么我们还是只能写下最大到 99999999 这样的数字
有限的宽度的便签,只能写下有限大小的数字
2、科学计数法
我们用科学计数法来表示这个数字。宇宙内的原子的数量,大概在 10 的 82 次方左右,我们就用 这样的形式来表示这个数值,不需要写下 82 个 0。
3、IEEE的标准
它定义了两个基本的格式。一个是用 32 比特表示单精度的浮点,也就是我们常常说的 float 或者 float32 类型、。另外一个是用 64 比特表示双精度的浮点数,也就是我们平时double 或者 float64 类型。
4、单精度的32位比特可以分为三部分
第一部分:符号位
第二部分:指数为
第三部分:有效数位
5、0和一些特殊数如何表示?
我们就要用上在 e 里面留下的 0 和 255 这两个表示,
这两个表示其实是两个标记位。在 e 为 0 且 f 为 0的时候,我们就把这个浮点数认为是 0。
至于其它的 e 是 0 或者 255 的特殊情况,你可以看下看下面这个表格,分别可以表示出无穷大、无穷小、NAN 以及一个特殊的不规范数
我们可以以 0.5 为例子。0.5 的符号为 s 应该是 0,f 应该是 0,而 e 应该是 -1,也就是对应的浮点数表示,就是 32 个比特。
四、总结和延伸
你会看到,在这样的表示方式下,浮点数能够表示的数据范围一下子打了很多,正是因为这个数对应的小数点的位置是“浮动”的它才被称为浮点数,
随着指数位e的值得不同,小数点的位置也在变动,对应的,前面的BCD编码的实数,就是小数点固定在某一位的方式,我们也就把它称为定点数
回到我们最开头,为什么我们用 0.3 + 0.6 不能得到0.9 呢?这是因为,浮点数没有办法精确表,示 0.3、0.6 和 0.9。事实上,我们拿出 0.1~0.9 这 9 个数,
其中只有 0.5 能够被精确地表示成二进制的浮点数,也就是 s = 0、e = -1、f = 0这样的情况
而 0.3、0.6 乃至我们希望的 0.9,都只是一个近似的表达。这个也为我们带来了一个挑战,就是浮点数无论是表示还是计算其实都是近似计算。那么,在使用过程中,
我们该怎么来使用浮点数,以及使用浮点数会遇到些什么问题呢?下一讲,我会用更多的实际代码案例,来带你看看浮点数计算中的各...“坑”。