0

I was just curious if anyone could explain to me why these different data types round differently in my code? (note: this is not how the variables are actually declared, it is how they are stored. I just displayed them like this for clarity)

double amount = 15 ;
double taxPercentage = 0.015;
decimal itemTax;

First, the un-rounded result:

itemTax = (decimal)(amount * taxPercentage);
  // itemTax returns -0.225

If I round first, then cast to decimal:

itemTax = (decimal)(Math.Round(amount * taxPercentage, 2, MidpointRounding.AwayFromZero));
  // itemTax returns -0.22 

If I cast to decimal first, then round:

itemTax = (decimal)(amount * taxPercentage);
itemTax = Math.Round(itemTax,2,MidpointRounding.AwayFromZero);
 //  itemTax returns -0.23

Does this have something to do with the way double types round vs. decimal types?

  • 2
    You should include assignments for `amount` and `taxPercentage` – Rufus L Mar 28 '18 at 18:10
  • In other words, this is not reproducing for me when I use `100` and `-.00025`. But doubles and decimals definitely have different precisions. Also, your first sample (the "un-rounded" result) does not compile unless you cast to a decimal. – Rufus L Mar 28 '18 at 18:21
  • What does `$"{ amount * taxPercentage : G20}"` print out? And `$"{ (decimal)(amount * taxPercentage) : G20}"`? Spot any diference? – InBetween Mar 28 '18 at 18:27
  • 2
    Also, you should be avoiding this issue altogether. `decimal` is in the language precisely for financial calculations that require exact calculations. Don't use `double` when money is involved because these kind of unpleasantnesses tend to appear. – InBetween Mar 28 '18 at 18:35
  • @InBetween I am aware of this and have said something. Database design is not up to me. I am trying to fix incorrect code and came across this. – Daniel Mitchell Mar 28 '18 at 19:39
  • @RufusL You are right. I was just being lazy. I edited and included the exact assignments and results. – Daniel Mitchell Mar 28 '18 at 19:41
  • 2
    Possible duplicate of [C# double to decimal precision loss](https://stackoverflow.com/questions/7453900/c-sharp-double-to-decimal-precision-loss) – Rufus L Mar 28 '18 at 19:58
  • @RufusL Not really, since I was primarily concerned with how type affected rounding. – Daniel Mitchell Mar 28 '18 at 20:56
  • Oh, I thought you were wondering why `amount * taxPercentage = 0.22499999999999998` but `(decimal)(amount * taxPercentage) == 0.225` (i.e. without any call to `Math.Round`) – Rufus L Mar 28 '18 at 21:07

1 Answers1

1

Indeed. Double (like float) is base-2 number and is actually an approximation of a decimal value. Unlike decimal values, it can't represent infinite precision numbers so your -0.025 values might really be -0.024999999999