0

I have this function:

int change(float c)
{
    float coins[] = {0.25, 0.10, 0.05, 0.01};
    int count[] = {0, 0, 0, 0};

    while(c > (0.00))
    {
        printf("I entered here\n");
        if((c-coins[0]) >= (0.00))
        {
            c -= coins[0];
            count[0]++;
            printf("-0.25, c = %.2f\n", c);
        }
        else if((c-coins[1]) >= (0.00))
        {
            c -= coins[1];
            count[1]++;
            printf("-0.10, c = %.2f\n", c);
        }
        else if((c-coins[2]) >= (0.00))
        {
            c -= coins[2];
            count[2]++;
            printf("-0.05, c = %.2f\n", c);
        }
        else if((c-coins[3]) >= (0.00))
        {
            c -= coins[3];
            count[3]++;
            printf("-0.01, c = %.2f\n", c);
        }
    }
    printf("(%d) 25 cents, (%d) 10 cents, (%d) 5 cents, (%d) 1 cents\n",
           count[0], count[1], count[2], count[3]);
    int total = count[0] + count[1] + count[2] + count[3];

    return total;
}

And whenever I try to enter 0.06 or 0.07, or any float number that will cause it to reach the last else if clause (the else if((c-coins[3]) >= (0.00))) it will cause an infinite loop.

Whereas if I enter 0.25, 0.10, 0.05 and their respective perfect multiples, the function goes smoothly. (Because maybe it wont reach the last else if clause).

And so when I debugged (using simple printf techniques), I found out that the variable c still enters the while loop even though it has reached 0.00. On some occasions, it would even reach -0.00 or -0.01 (and this only works if I changed the else if((c-coins[3]) >= (0.00)) to else only).

Example (assuming the else if in the code is already else only):
Input: 0.06

c-0.05, c = 0.01
c-0.01, c = -0.00 **<- WTF** 
(0) 25 cents, (0) 10 cents, (1) 5 cents, (1) 1 cents
Total Coins: 2

Someone explain this to me? Am I missing out some rules regarding float numbers here? Or some errors are caused by that last else if clause of mine?

Note: Changing the last else if to else may work but can affect the final answer. Also, changing the while condition to -0.00 or 0.001 doesn't work.

mafso
  • 5,433
  • 2
  • 19
  • 40
anobilisgorse
  • 906
  • 2
  • 11
  • 25
  • 1
    Tangent: don't use floating-point to represent pennies: http://floating-point-gui.de/ – Oliver Charlesworth Aug 16 '14 at 16:54
  • Hint: consider what happens for `c = 0.005`. – Oliver Charlesworth Aug 16 '14 at 16:55
  • Unrelated to your question, but the brackets in `if((c-coins[0]) >= (0.00))` don't contribute to readability (they reduce it). Go for `if(c-coins[0] >= 0)`. – mafso Aug 16 '14 at 17:59
  • @OliCharlesworth: OP is using floating-point to represent dollars. Had he/she been representing pennies, then they could have used an integer. In short, your insinuation is correct, OP should use `int` instead of `float`, the statement itself needs a slight correction... – barak manos Aug 16 '14 at 18:39
  • 1
    @barakmanos: Sure, I guess I intended "don't use float to represent *currency amounts*". – Oliver Charlesworth Aug 16 '14 at 18:41

1 Answers1

6

Floating point values (typically) use a binary representation. The only fraction in your coins array that can be represented exactly is 0.25. All the other values will be slightly smaller or larger than the correct value. This means that every arithmetic operation on these values, even simple substraction, will introduce small computation errors that will cause your comparisons and output to be faulty.

The best solution, in my opinion, is to use only integer types and perform all your calculations in cents (hundreds). You can print out the amounts using division and modulo.

int change(int cents)
{
   int coins[] = {25, 10, 5, 1};
   int count[] = {0, 0, 0, 0};

   while(cents > 0)
   {
     if((c-coins[0]) >= 0)
     {
        c -= coins[0];
        count[0]++;
        printf("-0.25, c = %d.%02d\n", c/100, c%100);
     }
     /* and so on */

You may want to use unsigned or long or both depending on your needs.

Nisse Engström
  • 4,738
  • 23
  • 27
  • 42