众所周知,使用==运算符比较双精度值是不安全的。在此示例中,它返回false:
double d1 = 0.11;
double d2 = 0.44 - 0.33;
Console.WriteLine(d1 == d2);但是,如果我们将值转换为decimal,它将返回true:
double d1 = 0.11;
double d2 = 0.44 - 0.33;
Console.WriteLine((decimal)d1 == (decimal)d2);比较double类型的小数是否总是安全的,或者在某些情况下可能会产生意想不到的结果?
更新:Hossein的例子很好,它表明它可能是错误的。但我更感兴趣的是,是否有相反的例子,当我们期望十进制值相等,但它们不是。更广泛地说,当我们从双精度转换为小数时,究竟发生了什么。
发布于 2017-05-12 14:35:06
众所周知,在.net中比较双精度值是不安全的。在本例中,它返回false
你搞错了什么是不安全的。
假设任意十进制表示法,即使它很短(以十进制写成),也完全用二进制浮点表示,这是不安全的。假设二进制浮点值之间的-生成与数学结果最接近的可表示浮点值以外的任何值都是不安全的(特别是,假设它总是生成数学结果是不安全的)。
d1 == d2是完全安全的,(decimal)d1 == (decimal)d2也是如此。第一个不会总是返回你想要的东西,但第二个也不会,因为它没有理由根据上面列出的原则。一旦计算了d1和d2,就已经完成了近似:
0.11应该是数学值11/100,但事实并非如此,它是最接近的可表示value;0.44减去0.33的数学结果可能无法精确表示,在这种情况下将使用最接近的可表示值。事实是,这些近似值是复合的,当在C#中添加转换为decimal的第三个近似值时,会产生您所期望的值,这纯粹是巧合。如果有什么是众所周知的,那就是在近似值发生后修复它已经太晚了,而且添加另一个近似值并没有真正的帮助。请参阅本文中的第一个示例Excel,它是微软的另一个可编程产品。
发布于 2017-05-12 13:03:03
在这种情况下,您可能会得到想要的结果,但通常您的答案是NO。如果将一个值存储在double中,然后将其转换为小数,并不会提高其精度(link)。
考虑下面的例子。等式返回true,但我们期望返回false。
double myDouble1 = 0.11;
double myDouble2 = 0.10999999999999999;
Console.WriteLine((decimal)myDouble1 == (decimal)myDouble2); //true, but we expect false但是如果您将这些值存储为十进制,那么您将获得正确的结果。
decimal myDecimal1 = 0.11M;
decimal myDecimal2 = 0.10999999999999999M;
Console.WriteLine(myDecimal1 == myDecimal2); //false发布于 2017-05-12 13:02:55
它总是安全的,提供了你知道浮点类型和小数类型之间的转换语义,和识别对实现代码的影响。
也就是说,除非您有充分的理由进行强制转换,否则遵循标准方法检查某些给定容差的相等性会更安全。(例如,(0.999 - 1.00) < 0.01。)
来自Explicit Numeric Conversions Table (C# Reference)
- If the source value is too small to be represented as a decimal, the result becomes zero.
- If the source value is NaN (not a number), infinity, or too large to be represented as a decimal, an OverflowException is thrown.
- When you convert decimal to float or double, the decimal value is rounded to the nearest double or float value.
https://stackoverflow.com/questions/43929468
复制相似问题