此问题与Math.Floor(double)
和Math.Ceiling(double)
决定为您提供上一个或下一个整数值的阈值有关。我很不安地发现阈值似乎与Double.Epsilon
无关,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
乘以公平的位置也无法解决问题:
Double.Epsilon
通过一些实验,我能够确定阈值大约在2.2E-16附近,这非常小,但比var digits = Math.Floor( Math.Log( n, 10 ) ) + 1
大得多。
出现这个问题的原因是我试图用公式n=1000
计算数字中的位数。此公式不适用于Math.Log( 1000, 10 )
(我偶然偶然发现),因为Math.Log10(double)
返回的数字比其实际值低4.44E-16。 (我后来发现内置的Double.Epsilon
提供了更准确的结果。)
阈值是否应该与{{1}}相关联,或者如果不是,则不应该记录阈值(我在MSDN官方文档中找不到任何相关内容)?
答案 0 :(得分:15)
阈值不应与Double.Epsilon相关联
没有
可表示的双精度数不均匀分布在实数上。接近于零有许多可表示的值。但是从零开始越远,可表示的双打越远。对于非常大数字,即使将1加到double也不会给你一个新值。
因此,您要查找的阈值取决于您的号码有多大。这不是一个常数。
答案 1 :(得分:10)
The value of Double.Epsilon
is 4.94065645841247e-324。由于浮点的工作方式,将此值加到3会导致3,结果为3。
double
有53位尾数,因此您可以添加的最小值会产生任何影响,比您的变量小约2 ^ 53倍。所以1e-16左右的声音听起来是正确的(数量级)。
所以回答你的问题:没有“门槛”; floor
和ceil
只是按照您期望的方式对他们的论点采取行动。
答案 2 :(得分:3)
这将是挥手而不是参考规格,但我希望我的直观解释"很适合你。
Epsilon表示可以表示的最小幅度,与零不同。考虑到双尾数的尾数和指数,这将是非常小的 - 想想10 ^ -324。小数点和第一个非零数字之间有三百多个零。
但是,Double
表示大约14-15位的精度。这仍然在Epsilon和整数之间留下310位零。
Double
被固定为某个位长度。如果您真的想要任意精度计算,则应使用任意精度库。并准备好它显着更慢 - 代表存储一个数字所需的所有325位数,如2+epsilon
,每个数字需要大约75倍的存储空间。该存储空间不可用,并且使用它进行计算肯定无法达到CPU的全速。