2

I have just began to learn C. I am writing a program that gives change back to the customer in quarters, nickels, dimes and pennies. For some reason when the while loop reaches 0 it does not break.

EDIT: This question is very similar to another question already on SO (Is floating point math broken?). I would keep this question for those searching for answers regarding the while loop, like myself, who had no idea the floating point number was causing the infinite while loop.

#include <stdio.h>
#include <cs50.h>

int main(void){
    float val;
    int quarters = 0;
    int dimes = 0;
    int nickels = 0;
    int pennies = 0;

    printf("How much change is due?: \n");

    val = GetFloat();

    while (val > 0){

        if (val >= 0.25){
            quarters += 1;
            val -= 0.25;
        }
        else if (val >= 0.1) {
            dimes += 1;
            val -= 0.1;
        }
        else if (val >= 0.05){
            nickels += 1;
            val -= 0.05;
        }
        else if (val >= 0.01){
            pennies += 1;
            val -= 0.01;
        }

        printf("%f \n", val);
    }

    printf("Quarters: %i\n", quarters);
    printf("Dimes: %i\n", dimes);
    printf("Nickels: %i\n", nickels);
    printf("Pennies: %i\n", pennies);

    return 0;
}

Any suggestions on how to handle?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Ctpelnar1988
  • 1,235
  • 3
  • 15
  • 38
  • 1
    Note that computer floating-point is not exact, and some of the numbers you're relying on (like the classic `0.1`) are not possible to represent without loss. What is it ending up printing? – unwind Sep 08 '16 at 10:05
  • 5
    Possible duplicate of [Is floating point math broken?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken) – alain Sep 08 '16 at 10:05
  • I actually did that at the bottom of the loop to see every output and it infinitely outputs `0.000000`. I usually test input with .41 . Though I just tested with .50 and .75 and those numbers work as expected. – Ctpelnar1988 Sep 08 '16 at 10:07
  • 2
    Print more decimal of `val` - see http://stackoverflow.com/questions/12761493/number-of-decimal-digits-in-c – Support Ukraine Sep 08 '16 at 10:08
  • my 2 pennies :) while( floorf(val * 100) / 100 > 0) //include math.h – Michael Frost Billing Sep 08 '16 at 10:14
  • when writing `float` literals, append a `f` to the end of the number, otherwise the code is actually using `double` values. Note: `0` in not a float value, use `0.0f` instead – user3629249 Sep 09 '16 at 01:57

2 Answers2

7

This is because float can't represent all values 100% correctly. For some input values your program will end up with valbeing greater than zero and less than 0.1. Then you have a deadlock.

Changing your print to:

printf("%0.30f \n", val);

will output:

0.009999995119869709014892578125

on my system.

A better approach could be to do the calculations in int instead. Something like:

#include <stdio.h>
#include <cs50.h>
#include <math.h>

int main(void){
    float val;
    int intval;
    int quarters = 0;
    int dimes = 0;
    int nickels = 0;
    int pennies = 0;

    printf("How much change is due?: \n");

    val = GetFloat();

    intval = roundf(100 * val);  // Multiply by 100 and convert to int

    // Use intval instead of val for the remaining code
    while (intval > 0){

        if (intval >= 25){     // note: 0.25 --> 100 * 0.25 --> 25 
            quarters += 1;     // similar for all other code below 
            intval -= 25;
        }
        else if (intval >= 10) {
            dimes += 1;
            intval -= 10;
        }
        else if (intval >= 5){
            nickels += 1;
            intval -= 5;
        }
        else if (intval >= 1){
            pennies += 1;
            intval -= 1;
        }

        printf("%d \n", intval );
    }

    printf("Quarters: %i\n", quarters);
    printf("Dimes: %i\n", dimes);
    printf("Nickels: %i\n", nickels);
    printf("Pennies: %i\n", pennies);

    return 0;
}
Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
0

Checking with a debugger, you will see that the floating point values are not accurate. In this example. after assigning val = (float)0.41 you can see in gdb:

(gdb) p val
$2 = 0.409999996

The endless loop happens because at the end val is bigger than 0 but smaller than 0.01

the easiest solution is to break in such case. Of course you might lose a penny:

while (val >= 0.01){
    ...
eyalm
  • 3,366
  • 19
  • 21