1

I have this switch statement that decreases the double itemCost (originally 0.80) by 0.20 each time. When it reaches 0.00 i want to execute some code. It works fine until it gets to 0.00 but instead of being 0.00 itemCost becomes 5.55111512312578E-17.

Output values for itemCost as I press the button which executes switch statement are:

0.60, 0.40, 0.20, 5.55111512312578E-17, -0.20, -0.40 etc

Code:

switch (codeString)
{
    case "20":
    {
        userAmount = userAmount + 0.20;
        itemCost = itemCost - 0.20;
        Console.WriteLine("" + itemCost);
        if (itemCost == 0.00)
        {
            giveChange();
            labelInstructions.Text = "giveChange";
        }
        else
        {
            string tempString = string.Format("{0:N2}", itemCost);
            labelInstructions.Text = "Please insert £" + tempString;
        }
        break;
    }
}

Anyone know why this weird behavior occurs and how to fix it?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Phil Hunter
  • 315
  • 2
  • 4
  • 15
  • Can you add in the loop that you are leaving out? This switch would only run once. The code doesn't show the original value of itemCost. – Ryan Gates Feb 12 '13 at 04:31
  • 2
    Are you sure the value isn't 5.557393938E-7 or something with E on the end? – Brian Webster Feb 12 '13 at 04:32
  • decimal is the appropriate .NET type for currency. – awright18 Feb 12 '13 at 04:34
  • Yes Brian, i edited the post. It ends with E-17 – Phil Hunter Feb 12 '13 at 04:36
  • 3
    [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – Habib Feb 12 '13 at 04:39
  • 1
    Please search SO before asking questions. Of the four and a half million or so questions on SO, probably 10% of them deal with the inaccuracies of floating point :-) – paxdiablo Feb 12 '13 at 04:44
  • .. But like the other four and a half million people, i did not know the problem laid with the inaccuracies of floating point. :P – Phil Hunter Feb 12 '13 at 04:59

1 Answers1

2

Since you are dealing with currency, you should switch over and use the Decimal datatype.

Floats and Doubles encounter very, very strange behavior when dealing with addition and subtraction as you get closer to 0.0.

It is critical when programming on all platforms to be very wary of floating point math when you need absolute precision. For example, game developers are forced to use floating-points, due to graphics-card, graphics-library, and performance restrictions. Typically, when they want to see if a value is zero, instead of comparing against zero, they do the following (pseudo code)

if AbsoluteValue(MyValue) < 0.001 then  //assume MyValue is zero.  

If you absolutely cannot switch to decimal, you can do something similar. If MyDouble is within Epsilon of Zero, where Epsilon is a const in the neighborhood of 0.00001, then force your value to zero. This is not recommended is 99% of scenarios. You really MUST use Decimal for currency, otherwise you will end up charging customers the wrong amount or suffering seemingly-random bugs.

Brian Webster
  • 30,033
  • 48
  • 152
  • 225
  • I will switch to decimal to see if it helps.. – Phil Hunter Feb 12 '13 at 04:39
  • I guarantee it will fix the problem if all of your math is done in Decimals. Good luck! Note, in order to hard-code a decimal, you can follow a number with the letter D. MyDecimal = 0.2D – Brian Webster Feb 12 '13 at 04:39
  • Ive changed everything to Decimal 0.00M for example. Now my output of itemCost goes 0.80, -0.20, -040, -0.60. – Phil Hunter Feb 12 '13 at 04:52
  • @Phil Hunter - Make sure both sides of your boolean expression are decimals. – Brian Webster Feb 12 '13 at 04:55
  • I got it working ok, works like a charm. I will mark you as answer and give it +1 for usefulness. Thanks. – Phil Hunter Feb 12 '13 at 04:57
  • What do you mean update my post, do you mean edit it and add the solution below? But you have provided solution? – Phil Hunter Feb 12 '13 at 05:01
  • @PhilHunter Yea Phil, don't worry about it now since you got it solved. I was referring to your first adjustment when it wasn't working yet. Sounds like you're all set. – Brian Webster Feb 12 '13 at 05:02
  • Ok, thanks. As long as Im following proper SO etiquette then its all good. ;) – Phil Hunter Feb 12 '13 at 05:05
  • You did fine here, despite the complaint about not "searching hard enough" before posting. If you don't know what's wrong, you don't know what to search for. If you do ever stumble across your own answer to your own question, you can post an answer to your own question and mark it accepted (if nobody posted a good enough answer for you). – Brian Webster Feb 12 '13 at 05:06