这是一个关于判断浮点数的精度问题,求指导,点数精度,大家应该都知道浮点数存在


大家应该都知道浮点数存在精度问题,所以问题就来了,我如何才能判断两个数是否近似相等,或者某个浮点数是否为0。
其实这是一个问题,对于前者,我们需要二者作差,然后与0进行比较。这样前者与后者就是同一个问题了,即如何判断某个浮点数是否为0。我所知道的比较简单但是不是很好的方法就是使用1e-7或者更小的数,如下所示(以单精度为例):

#include <iostream>#include <cfloat>using namespace std;int main(){    float num;    cout << "输入一个数:";    cin >> num;    if (num < 1e-7 && num > -1e-7)        cout << num << "近似为0" << endl;    else        cout << num << "不近似为0" << endl;    return 0;}

上述方式以C++代码为例。由于不同编程语言有不同的处理方式,大家可以不限制使用任何编程语言。当然,如果您有更通用的方式当然再好不过了。

计算机表示浮点数(float或double类型)都有一个精度限制,对于超出了精度限制的浮点数,计算机会把它们的精度之外的小数部分截断。因此,本来不相等的两个浮点数在计算机中可能就变成相等的了。例如:

float a=10.222222225,b=10.222222229数学上a和b是不相等的,但在32位计算机中它们是相等的。如果两个同符号浮点数之差的绝对值小于或等于某一个可接受的误差(即精度),就认为它们是相等的。不要直接用“==”或者“!=”对两个浮点数进行比较,但是可以直接用“<”和“>”比较谁大谁小。

浮点数的比较还是要根据实际存储规则来,因为浮点数是以二进制来存储的,而用二进制表示十进制是不能精确表示的,即使浮点数的十进制有效数字比较少,那也不一定能用二进制精确表示。为什么呢?
首先浮点数小数位的二进制是这样对应的:
小数后1位:0.5 (2^-1)
小数后2位:0.25 (2^-2)
...
小数位n位:2^-n
也就是说,任何一个浮点数的小数部分都是由2^-1 ... 2^-n组合而成的,这样就能理解为什么有效位数少的浮点数也不能精确表示了,比如0.3,就无法用上面的位数组合而精确表示出来,不信cout试试:

#include <iostream>#include <iomanip>int main(){    float a = 0.3f;    std::cout << std::setprecision(32) << a << std::endl;    return 0;}

输出:0.30000001192092896
而如果把0.3换成0.5,那就可以了,因为0.5可以用2^-1精确表示啊!同理,0.625也可以。
那我们平时为什么cout << 0.3;可以直接输出0.3呢?那是因为cout默认做了舍入处理

回到楼主的问题:如果是直接判断0.3 == 0.3,那没问题,因为同样的数字做了同样的表示,所以可以直接用'=='。如果是可以精确表示的数,比如0,则更是如此了。
但是如果判断0.1+0.2和0.3是否相等,那就不行了,因为他们都有精度损失,而损失的数值又不一样,所以不能直接比较需要用abs((0.1+0.2) - 0.3)<EPSILON这样的方法。

多小才是“足够小”,应该是由处理的具体问题决定的。比如用double表示金额的话,1e-4就可以认为是零了。而如果进行科学计算,恐怕1e-7还嫌太大。

<cfloat>中有定义DBL_EPSILON为与1.0最接近的差值。参见这里。

编橙之家文章,

评论关闭