将十进制转换为double时,我遇到了一个奇怪的问题。
以下代码返回true:
Math.Round(0.010000000312312m, 2) == 0.01m //true
但是,当我将其转换为double时,它返回false:
(double)Math.Round(0.010000000312312m, 2) == (double)0.01m //false
当我想使用Math.Pow时,我遇到了这个问题,因为十进制没有Math.Pow重载,所以我被迫将十进制转换为double。
这是记录在案的行为吗?当我被迫将十进制转换成双倍时,我怎么能避免它?
Visual Studio截图:
将Math.Round转换为以下结果加倍:
(double)Math.Round(0.010000000312312m, 2) 0.0099999997764825821 double
(double)0.01m 0.01 double
更新
好的,我正在重现这个问题如下:
UPDATE2
不幸的是,我无法在较小的项目中重现这个问题。我认为Eric的答案解释了原因。
答案 0 :(得分:11)
人们在这里的评论中报道,有时比较的结果是真的,有时它是假的。
不幸的是,这是可以预期的。 C#编译器,抖动和CPU都允许在 more 中执行双精度算术,而不是64位双精度,,因为他们认为合适。这意味着有时看起来像“相同”计算的结果可以在一次计算中以64位精度完成,在另一次计算中以80或128位精度完成,并且这两个结果的最后一位可能不同。
让我确保你理解我所说的“他们认为合适”。您可以以任何理由获得不同的结果。您可以在调试和零售中获得不同的结果。如果使编译器在常量中进行计算,并且如果使运行时在运行时进行计算,则可以得到不同的结果。调试器运行时,您可以获得不同的结果。您可以在运行时和调试器的表达式求值程序中获得不同的结果。 任何理由。双重算术固有地不可靠。这是由于浮点芯片的设计;在没有相当大的性能损失的情况下,这些芯片上的双重算术不能更加可重复。
由于这个原因和其他原因你几乎绝不会比较两个完全相等的双打。相反,减去双精度数,并查看差值的绝对值是否小于合理界限。
此外,您必须了解为什么将 double 舍入到两个小数位是一件困难的事情。非零有限双数是形式(1 + f)x 2 e 的数字,其中f是分母,其为2的幂,e是指数。很明显,不可能以这种形式表示0.01,因为没有办法让分母等于等于2的幂的分母中的10的幂。
双精度0.01实际上是二进制数1.0100011110101110000101000111101011100001010001111011 x 2 -7 ,十进制数为0.01000000000000000020816681711721685132943093776702880859375。那就是最接近的你可以在双倍中获得0.01。如果您需要完全那个值,那么使用小数。这就是为什么它被称为十进制。
顺便说一句,我已经在StackOverflow上多次回答了这个问题。例如:
另外,如果你需要“拆开”一个双重来看它的位是什么,这个我在一段时间后掀起的方便代码是非常有用的。它要求您安装Solver Foundation,但这是免费下载。
答案 1 :(得分:0)
这是记录在案的行为。十进制数据类型比double类型更精确。因此,当您从十进制转换为双精度时,可能会丢失数据。这就是您需要对类型进行显式转换的原因。
有关更多信息,请参阅以下MSDN C#参考:
十进制数据类型:http://msdn.microsoft.com/en-us/library/364x0z75(v=vs.110).aspx
双数据类型:http://msdn.microsoft.com/en-us/library/678hzkk9(v=vs.110).aspx
投射和类型转换:http://msdn.microsoft.com/en-us/library/ms173105.aspx