比较小数的最佳方法是什么?

时间:2013-02-07 20:17:33

标签: .net compare int floating-accuracy fuzzy-comparison

比较小数的最佳方法是什么?

假设我有2个值,例如3.453.44,可靠地比较它们的最佳方式是什么?

我在考虑将所有数字存储为345344,以便我只比较整数,并且只向用户显示带小数点的格式化数字。

另一个解决方案是使用自定义函数来测试差异,当差异小于0.01时,数字应相等。

其他可能的解决方案(更好的解决方案)是什么?

3 个答案:

答案 0 :(得分:3)

最常见的技术是使用epsilon(你描述的第二件事)。尽管如此,制作适用于所有输入数字的通用epsilon可能非常困难/不可能。如果你正在处理大约0.00001的数字或大约10亿的数字,0.01的epsilon对你来说可能是可怕的。阅读this以获得对epsilon技术的全面分析。

您描述的第一个解决方案在时间数学中很常见。所有内容都以整数个刻度表示。刻度可以代表1秒或1毫秒,或任何你想要的。如果愿意,您可以将它们转换为另一个单位的小数,或者比较它们。唯一的问题是你需要选择一个刻度尺寸,没有任何东西可以代表小于1个刻度单位。

答案 1 :(得分:0)

这也称为“模糊比较”,允许两个值稍微不同(公差,也称为“epsilon”)。通常情况下,这样的epsilon值大约为1E-61E-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);
}

第三个函数分别返回代码-101 a < ba == ba > 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是一个人机界面,通常用于不能容忍“搞笑”算术的货币应用程序。错误通常比缓慢更糟糕。