1

稍稍阅读后,这篇文章引起了我的兴趣:

考虑到 MSDN 的声明,我认为是的,这两个声明是等效的:

表示大于零的最小正双值。该字段是恒定的。

很想看看人们是怎么想的。

编辑:找到一台打开 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

4 回答 4

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​​ 到位)?

于 2013-11-26T16:57:33.003 回答
1

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

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

于 2013-11-26T16:52:11.783 回答
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)应该如此,但 C# 依赖于你来解决这个问题;如果被问到,它会很乐意将计算精确到该精度。== 0ddouble.Epison

于 2013-11-26T16:55:53.010 回答
0

Math.Abs(x) < double.Epsilon不幸的是,对于 ARM 系统来说,“等价于”的说法Math.Abs(x) == 0d根本不正确。

Double.Epsilon 上的 MSDN自相矛盾地指出

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

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

于 2017-03-23T03:59:48.180 回答