除法时的十进制舍入误差(C#)

时间:2011-05-06 11:15:06

标签: c# decimal rounding floating-accuracy

我基本上有四个数字(比如100,200,300,400),我需要计算概率为100 /(100 + 200 + 300 + 400),200 /(100 + 200 + 300 + 400)等等。

当我使用十进制数据类型来存储这些概率时,由于圆形问题,它们不会达到一个。在不使概率过于不准确的情况下,最好的方法是什么?基本上我做了很多次这个计算,所以我不想把所有的部分改成Math.Round的东西。 :|

2 个答案:

答案 0 :(得分:7)

解决方案很简单:如果你这样做会受到伤害,那就不要那么做

如果你有理性概率,即整数的比率概率,并且你希望它们只添加一个,那么不会将它们转换为十进制或双精度首先是。使用任意精度的有理类型来表示任意精度的有理数。

Microsoft Solver Foundation附带了一个任意精度的理性类型;你可以下载并使用它。或者,通过简单地创建一个具有两个BigIntegers作为分子和分母的不可变结构,然后编写所需运算符的实现,很容易编写自己的结构。

答案 1 :(得分:1)

没有调用Math.Round可以按照您想要的方式解决此问题。问题是所有的舍入必须一起工作 - 即。我们已经意识到他们没事,但他们一起看是错的。

处理除法舍入误差的一种方法是调整值以适应它:

List<decimal> decimals = new List<decimal>() { 100m, 200m, 300m, 300m };
decimal total = decimals.Sum();

List<decimal> probabilities = decimals.Select(x => x / total).ToList();
decimal sum = probabilities.Sum();
decimal error = 1.0m - sum;
Console.WriteLine("{0}, {1}", sum, error);

probabilities[0] += error; //put all of the error into the first item.
decimal newSum = probabilities.Sum();

Console.WriteLine(newSum);

更复杂的方法将错误分散在值上。例如,通过4个值而不是1来传播0.0000000000000000000000000004。