【问题标题】:What's the proper usage of approxEqual()?approxEqual() 的正确用法是什么?
【发布时间】:2012-01-02 01:17:59
【问题描述】:

起初我以为我只能依靠最大相对差异,但我错了。例如,如果a = 0.0b = 0.5,它们的相对差异为1.0。在这种情况下,approxEquals(lhs, rhs, maxRelDiff, maxAbsDiff) 依靠最大绝对差来确定两个浮点数是否相等。

这两个问题是:

  1. 如果默认值 (1e-2, 1e-5) 不够精确,我如何得出一个新的最大相对差和绝对差对? 1e-21e-5 是如何被选为默认值的?例如,如果我选择1e-4 作为我的最大相对差,那么最大绝对差是多少?

  2. 如何调整最大相对差值和绝对差值以使floatsdoubles 正常工作?

【问题讨论】:

    标签: floating-point d phobos


    【解决方案1】:

    检查source code 给了我这个(我删掉了范围的实现)

    bool approxEqual(T, U, V)(T lhs, U rhs, V maxRelDiff, V maxAbsDiff = 1e-5)
    {   
    
        if (rhs == 0)
        {
            return fabs(lhs) <= maxAbsDiff;
        }
        static if (is(typeof(lhs.infinity)) && is(typeof(rhs.infinity)))
        {
            if (lhs == lhs.infinity && rhs == rhs.infinity ||
                lhs == -lhs.infinity && rhs == -rhs.infinity) return true;
        }
        return fabs((lhs - rhs) / rhs) <= maxRelDiff
            || maxAbsDiff != 0 && fabs(lhs - rhs) <= maxAbsDiff;
    }
    

    最后一行是我们需要学习的内容:

    return fabs((lhs - rhs) / rhs) <= maxRelDiff
            || maxAbsDiff != 0 && fabs(lhs - rhs) <= maxAbsDiff;
    

    换句话说,如果数字相对相差不超过maxRelDiff的系数或绝对相差不超过@987654325,则函数返回true @

    所以使用maxRelDiff0.01(或1E-2)与2(十进制)数字的精度进行比较

    使用不同于 0 的 maxAbsDiff 允许接近 0 的数字被视为相等,即使相对差异大于 maxRelDiff

    编辑:基本上首先确定比较需要有多准确,并据此选择您的maxRelDiff,然后确定数字应该在什么时候等于0

    在 cmets 中的例子:

    approxEqual(1+1e-10, 1.0, 1e-10, 1e-30) 
    approxEqual(1+1e-10, 1.0, 1e-9, 1e-30)
    

    这比较接近于 1 的值,所以 maxRelDiff 在这里胜出,选择任何 maxAbsDiff(低于 maxRelDiff)不会改变任何东西

    approxEqual(0, 1e-10, 1e-10, 1e-30) 
    approxEqual(0, 1e-9, 1e-9, 1e-30)
    

    这会将接近 0 的值与 0 进行比较,因此 RelDiff (fabs((lhs - rhs) / rhs)) 将为 1,maxAbsDiff 胜过

    【讨论】:

    • 谢谢,但我非常了解 Phobos 中的实现。是的,该函数使用maxRelDiffmaxAbsDiff,但您没有抓住重点。这些问题与approxEqual() 的工作方式无关。相反,我想知道如何选择不同的maxRelDiffmaxAbsDiff 对而不是Phobos 中使用的默认对。我还想扩展这对以与 floatsdoubles 正常工作。
    • 并且只是为了说明为什么需要仔细选择这对:approxEqual(1+1e-10, 1.0, 1e-10, 1e-30)approxEqual(1+1e-10, 1.0, 1e-9, 1e-30) 不受 maxRelDiffmaxAbsDiff 值选择不当的影响,而是 approxEqual(0, 1e-10, 1e-10, 1e-30)approxEqual(0, 1e-9, 1e-9, 1e-30) 是。
    • 老兄最后几段仔细阅读,我加了一点解释
    【解决方案2】:

    虽然我无法回答您最初的问题,但我个人只是使​​用fabs 进行浮点比较:

    return fabs(f1 - f2) < 0.10;
    

    【讨论】:

    • 您正在计算 absolute difference 并将其与 0.10 进行比较。您不能只依赖绝对差异,而且您的 0.10 在大多数情况下都不够实用。
    • 如果 f1 = 0.01 和 f2 = 0.03,你有一个相当大的相对差异,但你的表达会说“他们是一样的”。
    • 就某些代码而言,这是我想要的行为。
    猜你喜欢
    • 2013-03-09
    • 2011-04-15
    • 1970-01-01
    • 2012-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多