【问题标题】:The right way to compare a System.Double to '0' (a number, int?)将 System.Double 与“0”(数字,整数?)进行比较的正确方法
【发布时间】:2011-09-29 16:52:01
【问题描述】:

抱歉,这可能是一个简单的愚蠢问题,但我需要知道才能确定。

我有这个if 表达式,

void Foo()
{
    System.Double something = GetSomething();
    if (something == 0) //Comparison of floating point numbers with equality 
                     // operator. Possible loss of precision while rounding value
        {}
}

这个表达式是否等于

void Foo()
{
    System.Double something = GetSomething();
    if (something < 1)
        {}
}

?因为那样我可能会遇到问题,例如输入if值为 0.9。

【问题讨论】:

  • // Comparison of floating point numbers with equality // operator. 你真的需要指定吗? :)
  • 见鬼没有。 0 到 1 之间有很多值。为什么不自己测试一下呢?
  • 我只是写了和 Resharper 一样的东西,以显示我的重点在哪里。
  • @Charles:还有很多小于0的数字。

标签: c# compare


【解决方案1】:

嗯,你需要多接近 0 的值?如果您进行大量“无限精度”的浮点运算可能会导致 0,那么您最终可能会得到“非常接近”0 的结果。

通常在这种情况下,您希望提供某种 epsilon,并检查结果是否在该 epsilon 内:

if (Math.Abs(something) < 0.001)

您应该使用的 epsilon 是特定于应用程序的 - 这取决于您在做什么。

当然,如果结果正好为零,那么简单的相等检查就可以了。

【讨论】:

  • 实际上,我需要它完全为零,这看起来如何?我找了 Double.Zero,但要知道运气。有一个常数对吗?顺便说一句,谢谢,我现在得到了 epsilon 部分:)
  • @radbyx:只需使用== 0。你有一个文字 - 这是相当恒定的:)
【解决方案2】:

如果something 是从something = 0 以外的操作结果分配的,那么您最好使用:

if(Math.Abs(something) < Double.Epsilon)
{
//do something
}

编辑:这段代码是错误的。 Epsilon 是最小的数,但不完全为零。当您希望将一个数字与另一个数字进行比较时,您需要考虑可接受的容差是多少。假设您不关心超出 .00001 的任何内容。这就是你要使用的号码。该值取决于域。但是,它几乎肯定不会是 Double.Epsilon。

【讨论】:

  • 这并不能解决舍入问题,例如Math.Abs(0.1f - 0.1d) &lt; double.Epsilonfalse
  • Double.Epsilon 对于这样的比较来说太小了。 Double.Epsilon 是 double 可以表示的最小正数。
  • 这没有意义,因为它实际上与与 0 比较相同。-1
  • 目标是在不使用 == 的情况下与 0 的概念进行比较。至少它在数学上是有意义的。我假设您手头有一个 double,并且您想将它与没有 == 的零概念进行比较。如果您的双精度值因任何原因(包括舍入)与 0d 不同,则测试填充返回 false。这种比较似乎对任何双精度都有效,并且只有当这个双精度小于可以表示的最小数字时才会返回真,这似乎是测试 0 概念的一个很好的定义,不是吗?
  • @MaurGi:你错了:double d = Math.Sqrt(10100)*2; double a = Math.Sqrt(40400); if(Math.Abs(a - d) &lt; double.Epsilon) { Console.WriteLine("true"); }
【解决方案3】:

您的somethingdouble,并且您已在该行中正确识别出它

if (something == 0)

我们在左侧 (lhs) 有一个 double,在右侧 (rhs) 有一个 int

但现在您似乎认为 lhs 将转换为 int,然后 == 符号将比较两个整数。这不是会发生什么。 double int 的转换是显式,不能“自动”发生。

相反,情况正好相反。 rhs 转换为double,然后== 符号成为两个双精度之间的相等测试。这种转换是隐式的(自动的)。

(某些人)认为写作更好

if (something == 0.0)

if (something == 0d)

因为这样您就可以立即比较两个双打。但是,这只是样式和可读性的问题,因为编译器在任何情况下都会做同样的事情。

在某些情况下,像 Jon Skeet 的回答那样引入“容忍度”也很重要,但这种容忍度也将是 double。如果您愿意,它可以当然是 1.0,但它不必是 [最不严格的正数] 整数。

【讨论】:

    【解决方案4】:

    如果您只是想抑制警告,请执行以下操作:

    if (something.Equals(0.0))
    

    当然,如果您知道漂移不是问题,这只是一个有效的解决方案。我经常这样做是为了检查我是否要除以零。

    【讨论】:

      【解决方案5】:

      老实说,我不认为这是平等的。考虑你自己的例子:something = 0.9,或 0.0004。 在第一种情况下它将是 FALSE,在第二种情况下它将是 TRUE。处理这种类型,我通常为我定义精度百分比并在该精度范围内进行比较。 取决于你的需要。 类似...

      if(((int)(something*100)) == 0) {
      
      
      //do something
      }
      

      希望这会有所帮助。

      【讨论】:

      • 某事必须完全为零。
      • 所以你是幸运的家伙,在这种情况下:)
      【解决方案6】:

      这里是出现问题的示例(在 LinQPad 中准备 - 如果您没有,请使用 Console.Writeline 而不是 Dump 方法):

      void Main()
      {
          double x = 0.000001 / 0.1;
          double y = 0.001 * 0.01; 
      
          double res = (x-y);
          res.Dump();
          (res == 0).Dump();
      }
      

      x 和 y 理论上相同,等于:0.00001,但由于缺乏“无限精度”,这些值略有不同。不幸的是,以通常的方式与 0 进行比较时,足以返回 false

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-06
        • 2017-06-21
        • 1970-01-01
        • 2023-04-02
        • 1970-01-01
        相关资源
        最近更新 更多