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

发布于 2024-11-03 08:10:49 字数 727 浏览 1 评论 0原文

如果你反思过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. 那里的 return 语句有什么意义?看来默认情况下如果num2大于num则num2的负值应该小于num。也许我在这里遗漏了一些东西,但这似乎是多余的。对我来说,这就像检查 5 是否大于 3,以及 -5 是否小于 3(作为示例)。

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).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

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

  2. 如果您对条件中的参数重新排序,然后将 num2 重命名为 tolerance,将 num 重命名为 diff ,它应该会变得清晰。

即:

return ((-num2 < num) && (num2 > num));
return ((num > -num2) && (num < num2));
return ((diff > -tolerance) && (diff < tolerance));
  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));
薔薇婲 2024-11-10 08:10:49

这些注释应该有助于理解这个方法:)

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

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

染柒℉ 2024-11-10 08:10:49

在谷歌上搜索该号码将我带到此页面
http://en.m.wikipedia.org/wiki/Machine_epsilon

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

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.

一刻暧昧 2024-11-10 08:10:49

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

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

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 :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文