【问题标题】:Unexpected Behavior of Math.Floor(double) and Math.Ceiling(double)Math.Floor(double) 和 Math.Ceiling(double) 的意外行为
【发布时间】:2012-03-28 22:50:24
【问题描述】:

这个问题是关于Math.Floor(double)Math.Ceiling(double) 决定给你上一个或下一个整数值的阈值。心烦意乱地发现阈值似乎与Double.Epsilon 无关,这是可以用double 表示的最小值。例如:

double x = 3.0;
Console.WriteLine( Math.Floor( x - Double.Epsilon ) );  // expected 2, got 3
Console.WriteLine( Math.Ceiling( x + Double.Epsilon) ); // expected 4, got 3

即使将Double.Epsilon 乘以一点也没有效果:

Console.WriteLine( Math.Floor( x - Double.Epsilon*1000 ) );  // expected 2, got 3
Console.WriteLine( Math.Ceiling( x + Double.Epsilon*1000) ); // expected 4, got 3

通过一些实验,我能够确定阈值在 2.2E-16 左右,非常小,但比Double.Epsilon 大得多。

出现这个问题的原因是我试图用公式var digits = Math.Floor( Math.Log( n, 10 ) ) + 1 计算数字中的位数。这个公式不适用于n=1000(我完全是偶然发现的),因为Math.Log( 1000, 10 ) 返回的数字与其实际值相差4.44E-16。 (后来我发现内置的Math.Log10(double) 提供了更准确的结果。)

阈值是否应该与Double.Epsilon 绑定,或者,如果不是,是否不应该记录阈值(我在 MSDN 官方文档中找不到任何提及)?

【问题讨论】:

标签: c# floating-point


【解决方案1】:

阈值不应该绑定到 Double.Epsilon

没有。

可表示的双精度数不是均匀分布在实数上的。接近于零有许多可表示的值。但是你离零越远,可表示的双打越远。对于非常大的数字,即使在双精度数上加 1 也不会给你一个新值。

因此,您要查找的阈值取决于您的人数有多大。它不是一个常数。

【讨论】:

    【解决方案2】:

    The value of Double.Epsilon is 4.94065645841247e-324。由于浮点的工作方式,将此值与 3 相加或相减得到 3。

    double 有 53 位尾数,因此您可以添加的最小值会产生任何影响,大约比您的变量小 2^53 倍。所以大约 1e-16 听起来是正确的(数量级)。

    所以回答你的问题:没有“门槛”; floorceil 只需按照您期望的方式处理他们的论点。

    【讨论】:

    • 所以基本上,双精度数中没有足够的有效数字来表示 3 和 3 - Double.Epsilon 之间的差异。通过此注释,原始海报阈值会有所不同,例如 11 或 111,因为需要额外的重要数字而不是 3。
    • @Rich:确实,但“阈值”适用于基本的浮点运算,不适用于floorceil
    • 我原以为 Double.Epsilon 是 2.220446049250313e-16。
    • @dan04:为什么?它是最小的非零值。
    • 因为machine epsilon is就是这样。
    【解决方案3】:

    这将是挥手而不是参考规范,但我希望我的“直观解释”适合你。

    Epsilon 表示可以表示的最小量级,即不为零。考虑到 double 的尾数 指数,这将非常小——想想 10^-324。小数点和第一个非零数字之间有三百多个零。

    但是,Double 表示大约 14-15 位的精度。这仍然在 Epsilon 和 整数 之间留下 310 位零。

    Doubles 固定为一定的位长。如果你真的想要任意精度计算,你应该使用任意精度库。并准备好让它显着变慢 - 代表存储诸如2+epsilon 之类的数字所需的所有 325 位数字将需要每个数字大约 75 倍的存储空间。该存储不是免费的,使用它进行计算当然不能以全 CPU 速度运行。

    【讨论】:

    • 不错的答案。我要改述一下,在精度边缘和浮点算术中较小的数字的减法或加法可能没有效果,这应该是预期的操作结果。所以这不是“意外”
    猜你喜欢
    • 1970-01-01
    • 2020-08-31
    • 2014-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多