【浮点数】0.1 + 0.2 != 0.3

一次 Python 课,讲解完 Python 的基础数据类型、运算符之后,有同学在课后提出了一个很有意思的问题,浮点数在进行数学运算的时候,会出现一些 “错误”,问题如下图所示。

【浮点数】0.1 + 0.2 != 0.3

为什么 0.1 + 0.1 、0.2 + 0.2 都是正确的,但是 0.1 + 0.2 就会出现如上图所示的问题?本文将介绍一下背后的设计原理,以及在有需要进行高精度计算的时候,如何避免此类问题。

首先我们需要了解一下,计算机在存储数字的时候是以二进制的方式进行存储(有限的 bit 位), 二进制表示遵循 IEEE 754 规范 [1] ,使用 IEEE754 规范的程序语言都会有浮点数精度的问题,0.30000000000000004 是一个介绍浮点数运算问题的网站 [2] ,并提供了相应编程语言的样例,C、C++、Go、Java、JavaScript、Python、R、Lua 等编程语言对浮点数的处理都会出现该现象 。

出现这个情况的原因是:

电脑用二进制表示小数(浮点数),而我们人类用十进制表示小数。

进制之间的差异导致电脑无法精确表示常用的十进制小数。十进制以10为基地,只能准确的表示使用基数素因数的分数。10的质因数是 2 和 5,因此,1/2、1/4、1/5、1/8 和 1/10 可以清晰表示,因为分母都是10的质因数。相比之下,1/3、1/6、1/7 和 1/9 都是循环小数,因为分母含有质因数 3 和 7。在二进制(基数为2)中,唯一的质因数是 2,因此只能准确的表示分母只有 2 作为质因数的分数。

通常意义下,十进制的 0.1 其实表示的是十分之一的意思,0.11 就代表 1/10 加上 1/10 的十分之一,也就是 1/10 + 1/100。以此类推,二进制下面的 0.1 其实就是1/2,等于 10 进制下面的 0.5。三进制下面的 0.1 等于 1/3,换算成十进制等于 0.3333333……是个无限循环小数。

以上例子说明,小数在改变进制之后可能变成无限位的,即在有限位的情况下无法准确地表示这些数字。如10 进制下的 0.1 就无法在2进制下(用有限位)精确地表示。1/10的分母10=2*5,其中5跟2互质,无法被2等分,因此用有限位的2进制小说无法表示。

【浮点数】0.1 + 0.2 != 0.3
竖式除法计算 1/10 的二进制表示

一般来说,使用浮点运算精度误差已足以解决各类计算问题。如遇到需要超高精度的运算,可以使用 decimal 模块利用字符串完成高精度运算。

参考文献

[1] IEEE754 规范 https://standards.ieee.org/standard/754-2008.html

[2] 浮点数运算问题 https://0.30000000000000004.com/

原创文章,作者:麒麟,如若转载,请注明出处:https://zhouqilin.tech/497.html

(1)
打赏 微信扫一扫 微信扫一扫
麒麟的头像麒麟
上一篇 2019-11-24 02:20
下一篇 2022-08-31 18:19

相关推荐