5

将小数转换为双倍时遇到奇怪的问题。

以下代码返回 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 重载。

这是记录在案的行为吗?当我被迫将小数转换为双倍时,如何避免它?

来自 Visual Studio 的屏幕截图:

来自 Visual Studio 的屏幕截图

铸造 Math.Round 以使我翻倍以下结果:

(double)Math.Round(0.010000000312312m, 2)   0.0099999997764825821   double
(double)0.01m   0.01    double

更新

好的,我将问题重现如下:

  1. 当我运行 WPF 应用程序并在它启动后检查手表中的输出时,我就像在空项目上一样。
  2. 有一部分应用程序将值从滑块发送到计算算法。我得到错误的结果,我在计算方法上设置了断点。现在,当我检查监视窗口中的值时,我得到错误(没有任何修改,我只是刷新监视窗口)。
  3. 一旦我在一些较小的项目中重现该问题,我将在此处发布。

更新2

不幸的是,我无法在较小的项目中重现该问题。我认为埃里克的回答解释了原因。

4

2 回答 2

12

人们在这里的评论中报告说,有时比较的结果是正确的,有时是错误的。

不幸的是,这是意料之中的。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.01000000000000000020816681711721686703294859378700937870。这是双倍中最接近0.01 的值。如果您需要准确表示该值,请使用 decimal。这就是为什么它被称为十进制

顺便说一句,我在 StackOverflow 上多次回答了这个问题的变体。例如:

为什么用括号分隔和用语句分隔时 C# 中的浮点精度不同?

此外,如果您需要“拆开”一个 double 以查看其位是什么,那么我不久前编写的这个方便的代码非常有用。它要求您安装 Solver Foundation,但这是免费下载的。

http://ericlippert.com/2011/02/17/looking-inside-a-double/

于 2013-08-21T15:36:38.487 回答
0

这是记录在案的行为。十进制数据类型比双精度类型更精确。因此,当您从十进制转换为双精度时,可能会丢失数据。这就是为什么您需要对类型进行显式转换的原因。

有关详细信息,请参阅以下 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

于 2013-08-21T15:30:10.703 回答