[英]Strange behavior when casting decimal to double
我在将小数转换为双精度时遇到奇怪的问题。
以下代码返回true:
Math.Round(0.010000000312312m, 2) == 0.01m //true
但是,当我将其转换为两倍时,它返回false:
(double)Math.Round(0.010000000312312m, 2) == (double)0.01m //false
我想使用Math.Pow时遇到了这个问题,由于十进制没有Math.Pow重载,因此不得不将十进制强制转换为双精度。
这是有据可查的行为吗? 当我不得不将十进制强制转换为双精度时如何避免呢?
Visual Studio的屏幕截图:
将Math.Round强制转换为以下结果的两倍:
(double)Math.Round(0.010000000312312m, 2) 0.0099999997764825821 double
(double)0.01m 0.01 double
更新
好的,我将问题重现如下:
更新2
不幸的是,我无法在较小的项目中重现该问题。 我认为埃里克(Eric)的回答解释了原因。
人们在这里的评论中报告说,比较的结果有时是正确的,有时是错误的。
不幸的是,这是意料之中的。 C#编译器,抖动和CPU都允许在超过 64位双精度上双打执行算术, 因为他们认为合适的 。 这意味着有时看起来像“相同”计算的结果可以在一个计算中以64位精度完成,而在另一计算中以80或128位精度完成,并且两个结果的最后一位可能有所不同。
让我确保您理解“他们认为合适”的意思。 无论出于何种原因,您都可以得到不同的结果。 您可以在调试和零售中获得不同的结果。 如果使编译器使用常量进行计算,并且使运行时在运行时进行计算,则可以获得不同的结果。 当调试器运行时,您可以获得不同的结果。 您可以在运行时和调试器的表达式评估器中获得不同的结果。 任何理由 。 双重运算本质上是不可靠的 。 这是由于浮点芯片的设计所致。 在不影响性能的前提下,无法使这些芯片上的双重算术具有更高的可重复性。
由于这个原因和其他原因, 您几乎绝不应该为完全相等而比较两个两倍 。 而是减去双精度值,然后查看差的绝对值是否小于合理范围。
此外,重要的是要了解为什么将双 精度数舍入到小数点后两位很困难。 非零有限双精度数是形式为(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,但这是免费下载。
这是记录的行为。 十进制数据类型比双精度类型更精确。 因此,当您从十进制转换为双精度时,可能会丢失数据。 这就是为什么要求您进行类型的显式转换的原因。
有关更多信息,请参见以下MSDN C#参考:
十进制数据类型: http : //msdn.microsoft.com/zh-cn/library/364x0z75(v=vs.110).aspx
双重数据类型: http : //msdn.microsoft.com/zh-cn/library/678hzkk9(v=vs.110).aspx
转换和类型转换: http : //msdn.microsoft.com/zh-cn/library/ms173105.aspx
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.