我正在尝试理解我反映的Microsoft的DoubleUtil.AreClose()代码

时间:2011-04-22 18:34:12

标签: c# compare double internals

如果您反映WindowsBase.dll > MS.Internal.DoubleUtil.AreClose(...),您将获得以下代码:

public static bool AreClose(double value1, double value2)
{
    if (value1 == value2)
    {
        return true;
    }
    double num2 = ((Math.Abs(value1) + Math.Abs(value2)) + 10.0) * 2.2204460492503131E-16;
    double num = value1 - value2;
    return ((-num2 < num) && (num2 > num));
}

我试图了解两件不同的事情:

  1. 他们在哪里提出了num2的公式?我想我只是不明白首先添加10.0的值的重要性,然后将所有结果乘以数字2.2204460492503131E-16。任何人都知道为什么这是使用的公式?

  2. 那里的退货声明有什么意义?似乎默认情况下,如果num2大于num而不是num2的否定值,则应小于num。也许我在这里遗漏了一些东西,但这似乎是多余的。对我而言,就像检查5是否大于3以及-5是否小于3(作为示例)。

4 个答案:

答案 0 :(得分:13)

  1. 这似乎是一个“容差”值,它基于所比较数字的大小。请注意,由于浮点数的表示方式,指数为0的数字之间的最小可表示差异为2 -53 或约1.11022×10 -16 。 (请参阅维基百科上的unit in the last placefloating point。)此处的常量恰好是该值的两倍,因此它允许在计算过程中累积的小舍入误差。

  2. 如果您对条件中的参数重新排序,然后将num2重命名为tolerance并将num重命名为diff,则应该清楚。

  3. 即:

    return ((-num2 < num) && (num2 > num));
    return ((num > -num2) && (num < num2));
    return ((diff > -tolerance) && (diff < tolerance));
    

答案 1 :(得分:4)

评论应该有助于理解这种方法:)

/// <summary>
/// AreClose - Returns whether or not two doubles are "close".  That is, whether or 
/// not they are within epsilon of each other.  Note that this epsilon is proportional
/// to the numbers themselves to that AreClose survives scalar multiplication.
/// There are plenty of ways for this to return false even for numbers which
/// are theoretically identical, so no code calling this should fail to work if this 
/// returns false.  This is important enough to repeat:
/// NB: NO CODE CALLING THIS FUNCTION SHOULD DEPEND ON ACCURATE RESULTS - this should be
/// used for optimizations *only*.
/// </summary>
/// <returns>
/// bool - the result of the AreClose comparision.
/// </returns>
/// <param name="value1"> The first double to compare. </param>
/// <param name="value2"> The second double to compare. </param>
public static bool AreClose(double value1, double value2)
{
    // in case they are Infinities (then epsilon check does not work)
    if (value1 == value2)
    {
        return true;
    }

    // This computes (|value1-value2| / (|value1| + |value2| + 10.0)) &lt; DBL_EPSILON
    double eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DBL_EPSILON;
    double delta = value1 - value2;
    return (-eps < delta) && (eps > delta);
}

<强>更新

这里的“神秘”价值DBL_EPSILON

    // Const values come from sdk\inc\crt\float.h
    internal const double DBL_EPSILON = 2.2204460492503131e-016; /* smallest such that 1.0+DBL_EPSILON != 1.0 */

src

答案 2 :(得分:2)

在Google上搜索该号码会引导我进入此页面 http://en.m.wikipedia.org/wiki/Machine_epsilon

在图形中,计算几何体可能会导致两个点,从像素的角度来看可能非常接近。由于在按位计算中进行舍入,因此浮点数可能得到很小的不同结果。因此,此方法检查数字是否接近机器epsilon范围内的另一个数字。

答案 3 :(得分:0)

我不知道为什么但是数字越接近0,差异必须小于通过检查。

对于小数字,返回是有意义的,例如取值0和1。没有第一部分就会通过但是0和1不够接近:)