是Math.Abs​​(x)< double.Epsilon相当于Math.Abs​​(x)== 0d?

时间:2013-11-26 16:15:50

标签: c# math double epsilon

经过一番轻松阅读后,this article引起了我的兴趣:

我认为是的,这两个陈述是等价的,给出了MSDN的声明:

  

表示大于零的最小正Double值。这个字段是不变的。

很想知道人们的想法。

编辑:找到一台带有VS的计算机并运行此测试。结果是,正如预期的那样,它们是等价的。

    [Test]
    public void EpsilonTest()
    {
        Compare(0d);
        Compare(double.Epsilon);
        Compare(double.Epsilon * 0.5);
        Compare(double.NaN);
        Compare(double.PositiveInfinity);
        Compare(double.NegativeInfinity);
        Compare(double.MaxValue);
        Compare(double.MinValue);
    }

    public void Compare(double x)
    {
        Assert.AreEqual(Math.Abs(x) == 0d, Math.Abs(x) < double.Epsilon);
    }

4 个答案:

答案 0 :(得分:4)

IL代码似乎对此有所了解。

Epsilon只是一个双数,分数部分为1,符号0,指数为0。 零是一个双数,小数部分为0,符号0,指数为0。

根据http://en.wikipedia.org/wiki/IEEE_754-1985,具有相同符号和指数的浮点数通常被比较,这意味着(x <1)与(x == 0)相同。

现在,是否有可能得到零不是分数= 0,指数= 0(我们不关心标志,那里有Math.Abs​​)?

答案 1 :(得分:1)

是的,据我所知,它们应该是等价的。这是因为没有差异的幅度小于epsilon,也不是非零。

我唯一的想法是关于double.NaN等值,我测试了它和PositiveInfinity等,结果是一样的。顺便说一下,将double.NaN与数字进行比较会返回false。

答案 2 :(得分:1)

我不确定你的“等价”是什么意思,因为这是一个非常模糊的术语。

如果您的意思是,.NET会认为任何小于double.Epsilon的值等于 0d,那么是的,因为您链接的文章清楚地表明了这一点。你可以很容易地展示这个:

var d1 = 0d;
var d2 = double.Epsilon * 0.5;
Console.WriteLine("{0:r} = {1:r}: {2}", d1, d2, d1.Equals(d2));
// Prints: 0 = 0: True

从这个意义上说,如果你以某种方式产生x的值小于double.Epislon,它已经已经存储在内存中作为零值,所以Abs(x)只是Abs(0)== 0d

但这是.NET用来保存浮点数的二进制表示的限制:它根本不能表示小于double.Epsilon的非零数字,因此它会循环。

这并不意味着这两个陈述是“等同的”,因为这完全取决于上下文。显然,4.94065645841247E-324 * 0.5不是零,而是2.470328229206235e-324。如果你正在进行的计算需要那么精确,而不是,那么它们就不相同了 - 而且你也试图用C#来做它们。

在大多数情况下,double.Epsilon的值太小而不具有任何价值,这意味着Abs(x)应该== 0d的值大于double.Epison,但是C#依靠你来解决这个问题;如果被问到的话,它会愉快地将计算精确到那么精确。

答案 3 :(得分:0)

不幸的是,声明&#34; Math.Abs(x) < double.Epsilon相当于Math.Abs(x) == 0d&#34;对于ARM系统来说根本不是真的。

MSDN on Double.Epsilon通过陈述

来反驳自己
  

在ARM系统上,Epsilon常量的值太小而无法检测到,因此等于零。

这意味着在ARM系统上,没有非负双值小于Double.Epsilon,因此表达式Math.Abs(x) < double.Epsilon只是说{{1}的另一种方式}}