Search code examples
c#decimalrounding-error

Decimal not rounding properly


I have a decimal called 'sum' and its value is 5824088.999120m, but when I try to round it to 3 decimals I get 5824088.998m instead of 5824088.999m. It decrements instead of leaving 5824088.999m.

Why is it? Here's my code:

List<decimal> quantityList = QuantityList();
List<decimal> priceList = PriceList();

decimal destination = 5824088.999M;
decimal sum = 0M;
bool lifesaver = false;

for (int x = 0; x < priceList.Count; x++)
{
    sum = 0M;
    for (int i = 0; i < 3500; i++)
    {
        priceList[x] += 0.001M;
        sum = 0M;
        for (int y = 0; y < priceList.Count; y++)
        {
            decimal multipleProduct = priceList[y] * quantityList[y];
            sum = sum + multipleProduct;
            Console.WriteLine(priceList[y] + " " + quantityList[y]);

            sum = Math.Round(sum, 3);
            Console.WriteLine("Sum: " + sum);
            Console.ReadKey();
            Console.WriteLine();
        }

        if (sum == destination)
        {
            Console.WriteLine("The new number is " + priceList[x] + " and it is the {0} element!", x);
            lifesaver = true;
            break;
        }
        else if (sum > destination)
        {
            Console.WriteLine("Limit exceeded!");
        }

        if (i == 3499)
        {
            priceList[x] -= 3.500M;
        }
        if (lifesaver == true)
        {
            break;
        }
    }//Second for loop

    if (lifesaver == true)
    {
        break;
    }
}//Main for loop

The lists are in another method.


Solution

  • It seems that you have round up error accumulation and thus the total is wrong:

      for (int y = 0; y < priceList.Count; y++) {
        ...
        sum = Math.Round(sum, 3); // <- this accumulates round up errors
        ...
      }
    

    imagine that the priceList contains

      priceList = new List<Decimal>() {
        1.0004M, 1.0004M, 1.0004M};
    

    while quantityList are all 1's; the sum will be

    1.000M, 2.000M, 3.000M
    

    while the actual total is

    Math.Round(1.0004M + 1.0004M + 1.0004M, 3) 
    

    3.001M. Possible remedy is not rounding up prematurely:

       for (int y = 0; y < priceList.Count; y++) {
          ...
          //DONE: comment out this: no premature rounding (within the loop)
          // sum = Math.Round(sum, 3);
          //DONE: but format out when printing out
          Console.WriteLine("Sum: {0:F3}", sum);
          ...
       } 
    
       // round up (if you want) after the loop
       sum = Math.Round(sum, 3);