您的位置:首页 >聚焦 >

世界球精选!0.1 + 0.2 != 0.3:Is floating point math broken?

2022-07-24 15:44:41    来源:程序员客栈

本文收录于 www.cswiki.top


(资料图)


看下面这段代码

0.1+0.2==0.3->Output:false0.1+0.2->Output:0.30000000000000004

0.1 + 0.2 != 0.3,什么情况?

先上答案:0.1 + 0.2 != 0.3 这个问题的症结在于:在现今的计算机中,数字的最终存储(表示)格式是二进制,是整数乘以 2 的幂。所以一切分母不是 2 的幂的有理数(例如 0.1,即 1/10)都是无法被计算机精确表示的。

下面来详细分析:

十进制小数与二进制的转换

整数十进制转二进制大伙都知道(除 2 取余法),我们来看看小数是怎么转二进制的

小数部分的转换不同于整数部分,它采用的是乘 2 取整法:将十进制中的小数部分乘以 2,得到一个数,将这个数的整数位作为二进制的一位,然后继续取其小数部分乘以 2 作为下一位,直到不存在小数为止

举个例子:3.14(十进制)

整数部分:

3(十进制)-> 0011(二进制)

小数部分:

0.14 x 2 = 0.28(将十进制 3中的小数部分 0.14乘以 2,得到一个数 0.28,将这个数的整数位 0作为二进制的一位,然后继续取其小数部分乘以 2 作为下一位,直到不存在小数为止),此时小数部分的二进制表示是 0xxx xxxx0.28 x 2 = 0.56(将十进制 0.28中的小数部分 0.28乘以 2,得到一个数 0.56,将这个数的整数位 0作为二进制的一位,然后继续取其小数部分乘以 2 作为下一位,直到不存在小数为止),此时小数部分的二进制表示是 00xx xxxx0.56 x 2 = 1.12(将十进制 0.56中的小数部分 0.56乘以 2,得到一个数 1.12,将这个数的整数位 1作为二进制的一位,然后继续取其小数部分乘以 2 作为下一位,直到不存在小数为止),此时小数部分的二进制表示是 001x xxxx.......

问题就出现了~

如果小数部分一直没法变成 0,那么小数部分的二进制表示将是无穷无尽的。

由于计算机的资源是有限的,所以没办法用二进制精确的表示这些小数部分一直没法变成 0 的数,只能用【近似值】来表示(现在基本采用的都是 IEEE 754 标准,https://en.wikipedia.org/wiki/IEEE_754#Basic_and_interchange_formats),这不可避免地就会造成精度缺失

Working with Floats in Programming

在平常写代码的时候,这个精度问题意味着我们需要使用舍入函数将浮点数四舍五入到我们需要的小数位,然后再显示它们。

还需要用【允许一定差距(allow some amount of tolerance)的比较】来替换浮点数之间的相等比较 ==,这意味着:

不要使用:if (x == y) { ... }

而是使用:if (abs(x - y) < myToleranceValue) { ... }


心之所向,素履以往,我是小牛肉,小伙伴们下篇文章再见

回复『春秋招』我拉你进交流群

关键词: 小数部分 二进制的 整数部分

相关阅读