I'm trying to understand Microsoft's DoubleUtil.AreClose() code that I reflected over

霸气de小男生 提交于 2019-12-03 20:42:56

问题


If you reflect over WindowsBase.dll > MS.Internal.DoubleUtil.AreClose(...) you'll get the following code:

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));
}

I'm trying to understand two different things:

  1. Where did they come up with the formula for num2? I guess I just don't understand the significance of first adding the value of 10.0 and secondly multiplying all the results by this the number 2.2204460492503131E-16. Anyone know why this is the formula used?

  2. What is the point of the return statement there? It seems that by default if num2 greater than num than the negated value of num2 should be less than num. Maybe I'm missing something here, but it seems redundant. To me it's like checking if 5 is larger than 3 and if -5 is less than 3 (as an example).


回答1:


  1. This appears to be a "tolerance" value that's based on the magnitude of the numbers being compared. Note that due to how floating point numbers are represented, the smallest representable difference between numbers with an exponent of 0 is 2-53 or approximately 1.11022 × 10-16. (See unit in the last place and floating point on Wikipedia.) The constant here is exactly two times that value, so it allows for small rounding errors that have accumulated during computations.

  2. If you reorder the parameters in the conditionals, and then rename num2 to tolerance and num to diff, it should become clear.

Viz.:

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



回答2:


The comments should help understanding this method :)

/// <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);
}

Update

And here the "mystic" value 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




回答3:


Searching on google for that number lead me to this page http://en.m.wikipedia.org/wiki/Machine_epsilon

In graphics, calculating geometry can result in little two points which may be very close from pixel point of view. Since floating point numbers may give little different result due to rounding done at bitwise calculation. So this method checks if number is close to another number within range of machine epsilon.




回答4:


I don't know why but the closer are the numbers to 0 the difference must be smaller to pass the check.

And for small numbers the return makes sense, take values 0 and 1 for example. Without the first part it would pass but 0 and 1 are not close enough :)



来源:https://stackoverflow.com/questions/5758726/im-trying-to-understand-microsofts-doubleutil-areclose-code-that-i-reflected

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!