C#中的15位数的Double Type精度是不是?
我正在测试Brainteasers的代码:
double d1 = 1.000001; double d2 = 0.000001; Console.WriteLine((d1 - d2) == 1.0);
结果是“假的”。 当我更改数据类型时:
decimal d1 = 1.000001M; decimal d2 = 0.000001M; decimal d3 = d1-d2; Console.WriteLine(d3 == 1);
该程序写出正确的答案:“真”。
此问题仅在浮点后使用6位数。 15位数的精度怎么样?
这与精度无关 – 它与表示舍入误差有关。
System.Decimal
能够表示大的浮点数,并且可以显着降低发生任何舍入错误的风险,例如您所看到的错误。 System.Single
和System.Double
不具备此function,并将关闭这些数字并创建类似于您在示例中看到的问题。
System.Decimal
使用缩放因子来保存小数位的位置,从而允许精确表示给定的浮点数,而System.Single
和System.Double
只能尽可能接近您的值。
有关更多信息,请参阅System.Double
:
请记住,浮点数只能近似一个十进制数,并且浮点数的精度决定了该数字接近十进制数的准确程度。 默认情况下,Double值包含15个十进制数字的精度,但内部最多保留17位数。 浮点数的精度有几个结果:
对于特定精度看起来相等的两个浮点数可能不会相等,因为它们的最低有效数字是不同的。
如果使用十进制数,使用浮点数的数学运算或比较运算可能不会产生相同的结果,因为浮点数可能不完全接近十进制数。
通常,检查浮点值是否相等的方法是检查near -equality,即检查接近该数据类型的最小值(称为epsilon )的差异。 例如,
if (Math.Abs(d1 - d2) <= Double.Epsilon) ...
这测试以查看d1
和d2
是否由相同的位模式表示给出或取最低有效位。
更正 (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) ...
换句话说,取d1
和d2
之间的绝对差值,然后将其除以d1
和d2
的最大值, 然后将其与Epsilon
进行比较。
参考
• http://msdn.microsoft.com/en-us/library/system.double.epsilon.aspx
• http://msdn.microsoft.com/en-us/library/system.double.aspx#Precision
十进制类型实现十进制浮点,而double是二进制浮点。
十进制的优点是它在舍入方面表现得像人类一样,如果用十进制值初始化它,那么该值将按照您指定的方式精确存储。 这仅适用于有限长度的十进制数,并且在可表示的范围和精度内。 如果你用1.0M / 3.0M初始化它,那么就不会像在纸上写0.33333一样精确地存储它。
如果初始化带有小数的二进制FP值,它将从人类可读的十进制forms转换为很少完全相同的二进制表示。
十进制类型的主要目的是用于实现财务应用程序,在.NET实现中它也具有比double高得多的精度,但是硬件直接支持二进制FP,因此明显快于十进制FP操作。
请注意,double精确到大约15 位有效数字而不是15 位小数 。 d1初始化为7有效数字值而不是6,而d2仅有1有效数字。 它们具有显着不同的幅度这一事实也无济于事。
浮点数的想法是它们对于特定数量的数字不精确。 如果您想要这种function,您应该查看decimal
数据类型。
精度不是绝对的,因为不可能精确地在十进制和二进制数之间进行转换。
在这种情况下,当以二进制表示时,.1十进制将永远重复。 它转换为.000110011001100110011 …并永远重复。 精确度不会精确存储。
避免比较浮点数的相等性。