比较小数的最佳方法是什么?
假设我有2个值,例如3.45
和3.44
,可靠地比较它们的最佳方式是什么?
我在考虑将所有数字存储为345
和344
,以便我只比较整数,并且只向用户显示带小数点的格式化数字。
另一个解决方案是使用自定义函数来测试差异,当差异小于0.01
时,数字应相等。
其他可能的解决方案(更好的解决方案)是什么?
答案 0 :(得分:3)
最常见的技术是使用epsilon(你描述的第二件事)。尽管如此,制作适用于所有输入数字的通用epsilon可能非常困难/不可能。如果你正在处理大约0.00001的数字或大约10亿的数字,0.01的epsilon对你来说可能是可怕的。阅读this以获得对epsilon技术的全面分析。
您描述的第一个解决方案在时间数学中很常见。所有内容都以整数个刻度表示。刻度可以代表1秒或1毫秒,或任何你想要的。如果愿意,您可以将它们转换为另一个单位的小数,或者比较它们。唯一的问题是你需要选择一个刻度尺寸,没有任何东西可以代表小于1个刻度单位。
答案 1 :(得分:0)
这也称为“模糊比较”,允许两个值稍微不同(公差,也称为“epsilon”)。通常情况下,这样的epsilon值大约为1E-6
到1E-10
,但您可以找到更适合更小或更大值的应用程序:在您的示例中,epsilon不应小于1E-2 = 0.01
一旦找到了符合您需求的epsilon值,您就可以编写以下一组比较函数,如下所示(用C和C ++的通用子集编写;它们应该适用于几乎所有面向对象/过程的语言微小的变化):
const double fuzzyEpsilon = 1E-6; // just an example!
bool fuzzyEqual(double a, double b) {
return (abs(a - b) <= fuzzyEpsilon);
}
bool fuzzyUnqual(double a, double b) {
return (abs(a - b) > fuzzyEpsilon);
}
int fuzzyCompare(double a, double b) {
return ((a - b) > fuzzyEpsilon) - ((b - a) > fuzzyEpsilon);
}
第三个函数分别返回代码-1
,0
,1
a < b
,a == b
,a > b
进行模糊比较(类似于strcmp
)。该实现假定编程语言隐式地将布尔值转换为0
(false)和1
(true)。如果没有,请使用以下内容:
int fuzzyCompare(double a, double b) {
return (a - b) > fuzzyEpsilon ? 1 :
((b - a) > fuzzyEpsilon ? -1 : 0);
}
答案 2 :(得分:0)
以二进制实数表示十进制值是近似值,导致各种奇怪的行为。精度通常会随着进一步算术而降低,尤其是附近值的减法。但是,在比较它们之前,可以通过舍入到最小位数来清除单个值以进行比较。例如,V = round(V * 1e14)/ 1e14将任何值V舍入到14个十进制数字。可以自信地比较两个这样的值以获得相等性。 64位实数具有15.65的精度,因此舍入到14位(或更小)会提供一些错误空间。
是的,乘法,舍入()和除法序列很昂贵。但是,decimal是一个人机界面,通常用于不能容忍“搞笑”算术的货币应用程序。错误通常比缓慢更糟糕。