C#中的15位数的Double Type精度是不是?

Bro*_*dow 5 c# precision types

我正在测试Brainteasers的代码:

        double d1 = 1.000001;

        double d2 = 0.000001;

        Console.WriteLine((d1 - d2) == 1.0);
Run Code Online (Sandbox Code Playgroud)

结果是"假的".当我更改数据类型时:

        decimal d1 = 1.000001M;

        decimal d2 = 0.000001M;

        decimal d3 = d1-d2;

        Console.WriteLine(d3 == 1);
Run Code Online (Sandbox Code Playgroud)

该程序写出正确的答案:"真".

此问题仅在浮点后使用6位数.15位数的精度怎么样?

And*_*are 28

这与精度无关 - 它与表示性舍入误差有关.

System.Decimal能够表示大浮点数,并且可以显着降低发生任何舍入错误的风险,例如您所看到的错误. System.Single并且 System.Double不具备此功能,并且会将这些数字四舍五入并创建类似于您在示例中看到的问题.

System.Decimal使用缩放因子来保持小数位的位置,从而允许精确表示给定的浮点数,System.Single而且 System.Double只能尽可能接近您的值.

有关更多信息,请参阅System.Double:

请记住,浮点数只能近似一个十进制数,并且浮点数的精度决定了该数字近似于十进制数的准确程度.默认情况下,Double值包含15个十进制数字的精度,但内部最多保留17位数.浮点数的精度有几个结果:

  • 对于特定精度看起来相等的两个浮点数可能不相等,因为它们的最低有效位数不同.

  • 如果使用十进制数,使用浮点数的数学或比较操作可能不会产生相同的结果,因为浮点数可能不完全接近十进制数.


Dav*_*ble 8

通常,检查浮点值是否相等的方法是检查near -equality,即检查接近该数据类型的最小值(称为epsilon)的差异.例如,

if (Math.Abs(d1 - d2) <= Double.Epsilon) ...
Run Code Online (Sandbox Code Playgroud)

这测试以查看d1d2是由相同的位模式表示给出还是取最低有效位.

更正 (2015年3月2日新增)

经过进一步检查,代码应该更像这样:

// Assumes that d1 and d2 are not both zero
if (Math.Abs(d1 - d2) / Math.Max(Math.Abs(d1), Math.Abs(d2)) <= Double.Epsilon) ...
Run Code Online (Sandbox Code Playgroud)

换句话说,取d1和之间的绝对差值d2,然后将其除以最大的d1d2,然后将其与之比较Epsilon.

参考
http://msdn.microsoft.com/en-us/library/system.double.epsilon.aspx
http://msdn.microsoft.com/en-us/library/system.double.aspx#Precision


Cli*_*ord 6

小数类型实现十进制浮点而是二进制浮点数.

十进制的优点是它在舍入方面表现得像人类一样,如果用十进制值初始化它,那么该值将按照您指定的方式精确存储.这仅适用于有限长度的十进制数,并且在可表示的范围和精度内.如果你用1.0M/3.0M初始化它,那么就不会像在纸上写0.33333一样精确地存储它.

如果初始化带有小数的二进制FP值,它将从人类可读的十进制形式转换为很少完全相同的二进制表示.

十进制类型的主要目的是实现财务应用程序,在.NET实现中它也具有远高于double的精度,但二进制FP直接由硬件支持,因此明显快于十进制FP操作.

请注意,double精确到大约15 位有效数字,而不是15 位小数.d1初始化为7有效数字值而不是6,而d2仅有1有效数字.它们具有显着不同的幅度这一事实也无济于事.