【问题标题】:I'm trying to understand Microsoft's DoubleUtil.AreClose() code that I reflected over我试图理解我反映的微软的 Do​​ubleUtil.AreClose() 代码
【发布时间】:2011-08-11 03:38:30
【问题描述】:

如果您对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(例如)。

【问题讨论】:

  • 该值被称为Machine Epsilon,它是浮点系统中两个数字之间的最小差值。
  • 5大于-7,但-5不小于-7
  • @juharr:现在更有意义了 :)

标签: c# .net compare double internals


【解决方案1】:

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

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

【讨论】:

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

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

    即:

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

    【讨论】:

    • 检查 diff 是否大于否定容差以及是否小于容差似乎仍然有点多余。我无法理解返回值的一部分计算为真,而另一部分计算为假的情况。
    • @myermian 两个值的差可以是负数(因为没有取绝对值);事实上,它可能是一个非常大的负数。假设公差为 0.01,两个值之间的差值为 -50.0。 -50.0 &lt; 0.01 是真的,但显然这两个值并不接近;您还需要检查-50.0 &gt; -0.01 是否为假。
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

      • 您使用什么工具来获取实际的 cmets? Red Gate 的 .NET Reflector(旧版本 - 非专业版)似乎无法让我获得 cmets。
      • @myermian:我使用 google 快速搜索 codeplex(请参阅答案底部的 src-link)
      • 另外,我想知道为什么这不是微软的扩展方法并被微软公开。这似乎是一个有用的功能。
      • 啊,这是 WPF 工具包的源代码,它可能与 .NET 4 dll 的注释相同。我一直希望有一种方法可以真正看到 .NET 4 的评论,而不仅仅是反映在上面的代码。
      猜你喜欢
      • 2020-09-10
      • 2019-02-25
      • 1970-01-01
      • 1970-01-01
      • 2020-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多