【问题标题】:What is the best way to compare decimals?比较小数的最佳方法是什么?
【发布时间】:2013-02-07 20:17:33
【问题描述】:

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

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

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

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

还有哪些可能的解决方案(更好的解决方案)?

【问题讨论】:

  • 我会测试差异:if ((flOne - flTwo)
  • 3.45 不大于 3.44?为什么要他们平等?
  • 你能用 fixed point 数学代替吗?一个例子是将浮点米转换为定点毫米。
  • 很大程度上取决于这些数字的来源以及它们的含义。例如,如果我可能想将两个数字视为相等,如果它们是具有舍入误差的浮点计算的结果,但如果它们是直接输入则不同。

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


【解决方案1】:

最常见的技术是使用 epsilon(您描述的第二件事)。但是,制作一个适用于所有输入数字的通用 epsilon 可能非常困难/不可能。如果您正在处理 0.00001 左右的数字或 1000000000 左右的数字,那么 0.01 的 epsilon 对您来说可能会很糟糕。阅读this,了解对 epsilon 技术的全面分析。

您描述的第一个解决方案在时间数学中非常常见。一切都以整数刻度表示。刻度可以代表 1 秒或 1 毫秒,或任何你想要的。然后,您可以根据需要将它们转换为另一个单位的小数,或进行比较。唯一的问题是您确实需要选择刻度大小,没有任何东西可以表示小于 1 个刻度单位。

【讨论】:

    【解决方案2】:

    这也称为“模糊比较”,允许两个值略有不同(容差,也称为“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 &lt; ba == ba &gt; b进行模糊比较(类似于strcmp)。该实现假定编程语言将布尔值隐式转换为0 (false) 和1 (true)。如果没有,请使用以下内容:

    int fuzzyCompare(double a, double b) {
        return (a - b) > fuzzyEpsilon ? 1 :
              ((b - a) > fuzzyEpsilon ? -1 : 0);
    }
    

    【讨论】:

    • strcmp 不是你应该为新代码建模的东西,它已经过时了。
    • @Dave 但这是表示比较结果的仅有的两种好方法之一。另一个是枚举。
    • 你为什么要首先制作这个功能?为什么6个比较没有不同的功能?为了避免一个数字是 另一个数字(以及其他逻辑异常),您必须添加额外的逻辑。
    • @Dave 嗯,可以根据需要实现。我写过“你可以写”,所以如果有人对类似于strcmp 的“比较”方法感兴趣,那就是。通常,如果您只对更小或更大感兴趣(实际上并不期望相等的值,因此只是任意视为小于或更大),则不会进行模糊比较。
    【解决方案3】:

    用二进制实数表示十进制值是近似的,导致各种奇怪的行为。精度通常会随着进一步的算术而降低,尤其是附近值的减法。但是,可以通过在比较它们之前四舍五入到最小位数来清理单个值以进行比较。例如 V = round (V * 1e14)/1e14 将任何值 V 舍入为 14 位十进制数字。可以自信地比较两个这样的值是否相等。 64 位实数具有 15.65 小数精度,因此四舍五入到 14 位(或更少)提供了一些错误空间。

    是的,乘法、舍入( ) 和除法序列很昂贵。然而,十进制是一种人机界面,通常用于不能容忍“有趣”算术的货币应用程序。犯错通常比缓慢更糟糕。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多