2011-03-03 100 views
2

我明白这个问题背后的原理,但它让我很头痛,认为这在整个我的应用程序中都在发生,我需要找到解决方案。C#数学给出了错误的结果!

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的数字。不幸的是,由于我将这个数字四舍五入,这给出了错误的答案。

我已经阅读过有关使用小数而不是双精度的方法,但是我无法用小数来替换Double的每个实例。有没有更简单的方法来解决这个问题?

+1

舍入为3位小数,然后舍入为2位小数?啊...并且要知道Math.Round使用Banker的四舍五入来循环,所以0。5时间缩短了一半,一半时间缩短了。有一个选项可以使用“标准”舍入。这是MidpointRounding.AwayFromZero。 – xanatos 2011-03-03 10:31:20

+1

由于我们在这里讨论的是货币数据,我认为你应该尽快进行重构。 – linepogl 2011-03-03 10:33:56

回答

15

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

但是,您应该真正了解开始的情况......例如,为什么Value不等于141.1。

我对这两篇文章:

+1

+1因为有一些预先写好的书,以防万一。 – 2011-03-03 10:33:09

0

而不是使用圆形圆的数量,你可以使用一些功能,你自己写的,它使用一个小小量当四舍五入以允许错误时。这是你想要的答案。

你不想要的答案,但是我要说的是,如果你想要精确度,并且由于你正在用你的例子来判断你的金钱,你应该不要使用二进制浮点数学。二进制浮点本质上不准确,有些数字不能正确表示。使用基数为10的浮点的Decimal将是一个更好的方法,并且可以避免您在双打中造成代价高昂的错误。

+4

他不应该使用*二进制*浮点类型。请注意,'decimal'也是一个浮点类型。还有一些数字不能准确表示......但所有*十进制*数字(在相关范围和精度内)都可以准确表示。 – 2011-03-03 10:32:19

+0

感谢您的更正。编辑批准。 – Stewart 2011-03-03 12:05:32

3

您应该使用decimal - 这就是它的用途。

浮点运算的行为?这正是它所做的。它具有有限的精确度。并非所有的数字都可以完全表示。事实上,有无限数量的实数值,只有有限的数字可以表示。 decimal对于这个应用程序的关键在于它使用基数10表示 - double使用基数2.

0

在花了大部分时间尝试将每个“double”的实例替换为“decimal”并实现I正在战斗失败的战斗,我再看看我的回合功能。这可能是有用的那些谁也无法实现正确的解决方案:

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

通过首先将值强制转换为十进制,然后调用Math.Round,这将返回“正确”的价值。