C#Maths给出了错误的结果!

我理解这个问题背后的原理,但是让我头疼的是认为这在整个应用程序中都会发生,我需要找到解决方案。

double Value = 141.1; double Discount = 25.0; double disc = Value * Discount / 100; // disc = 35.275 Value -= disc; // Value = 105.824999999999999 Value = Functions.Round(Value, 2); // Value = 105.82 

我用双打代表很小的数字。 不知何故,在计算141.1-35.275中,结果的二进制表示给出了一个仅为0.0000000000001的数字。 不幸的是,由于我正在舍入这个数字,这给出了错误的答案。

我已经阅读过使用Decimals而不是Doubles但我不能用Decimal替换Double的每个实例。 有没有更简单的方法来解决这个问题?

如果您正在寻找自然十进制值的精确表示, 需要在每个地方替换doubledecimal 。 您只是使用了错误的数据类型。 如果你在short地方使用short整数然后发现你需要应对比支持更大的值,你会怎么做? 这是同样的交易。

但是,你应该真正试着去理解一下开始的事情……例如,为什么Value并不完全等于141.1。

我有两篇文章:

  • .NET中的二进制浮点
  • .NET中的十进制浮点数

你应该使用decimal – 这就是它的用途。

浮点运算的行为? 这正是它的作用。 它的有限精度有限。 并非所有数字都可以完全表示。 实际上,存在无数个实数值,并且只有有限数可以表示。 对于这个应用程序, decimal的关键是它使用基数10表示 – double使用base 2。

您可以使用自己编写的某些函数代替使用Round来舍入数字,该函数在舍入时使用小epsilon以允许出错。 这就是你想要的答案。

你不想要的答案,但无论如何,我要提供的是,如果你想要精确,并且因为你正在用你的例子判断你可能做的钱,你不应该使用二进制浮点数学。 二进制浮点本质上是不准确的,有些数字无法正确表示。 使用十进制数,它可以实现基数为10的浮点数,这将是一个更好的方法,可以避免你用你的双打犯下代价高昂的错误。

在早上的大部分时间里尝试将’double’的每个实例替换为’decimal’并意识到我正在打一场失败的战斗之后,我又看了一下我的Round函数。 这可能对那些无法实现正确解决方案的人有用:

 public static double Round(double dbl, int decimals) { return (double)Math.Round((decimal)dbl, decimals, MidpointRounding.AwayFromZero); } 

首先将值转换为小数,然后调用Math.Round,这将返回“正确”值。