0

I am trying to count the number of coins remained in order to give the client the least amount of coins.

But the last coin which is 0.01 always miscounts it.

I always get the number of coins -1.

get_float() is a special function to accept a float input.

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

int main(void) {
    float coin;
    int count;
    do {
        coin = get_float("enter the owed change?");
        //printf("your cash %f", coin);
        printf("\n");
    } while (coin <= 0.00 || coin > 1.00);

    //if (coin > 0.000000 && coin < 1.000000) {
        count = 0;
        while ((coin - 0.25) > 0) {
            coin -= 0.25;
            count++;
        }
        while ((coin - 0.10) > 0) {
            coin -= 0.10;
            count++;
        }
        while ((coin - 0.05) > 0) {
            coin -= 0.05;
            count++;
        } 
        while ((coin - 0.01) > 0) {
            coin -= 0.01;
            count++;
        }
        if (coin == 0.01) {
             count++;
        } 
        //if (coin == 0.00) {
             printf("%d", count);
        //}
    //}
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
Ahmad Ali
  • 704
  • 1
  • 10
  • 28
  • 2
    Never compare floats with discrete values. – unalignedmemoryaccess Jan 06 '19 at 16:09
  • 2
    Tip: multiply coin by 100 and move to integers. – KamilCuk Jan 06 '19 at 16:14
  • 2
    Sham XR, Code does not demonstrate that "last coin which is 0.01". How did you determine that? Try adding `printf("your cash %.20f", coin);` in various locations to understand why code fails. – chux - Reinstate Monica Jan 06 '19 at 16:20
  • 4
    You should use integer for currency representation. count should be in cents. arithmetic with integers is more efficient and more accurate. – SHR Jan 06 '19 at 16:33
  • 1
    @shr [integer for currency](https://stackoverflow.com/questions/54063372/counting-the-least-amount-of-changes-to-give-your-client/54063563#comment94960219_54063372) has [weaknesses](https://stackoverflow.com/a/32214586/2410359) too. Reasonable advice to use wide integers for learners, yet that is not always best for more complex financial code. – chux - Reinstate Monica Jan 06 '19 at 23:37

2 Answers2

2

Typical float can encode exactly about 232 different values.
0.10,0.05,0.01 are all not of them.
Instead a very nearby value is used.
It is this approximation that leads to the problem.

Instead, use whole number of 0.01 (cents) @Kamil Cuk:

// prototype for `round()`
#include <math.h>

do {
  //  coin = get_float("enter the owed change?");
  coins = round(100.0 * get_float("enter the owed change?");
  printf("\n");
// } while(coin<=0.00 || coin>1.00);
} while(coin <= 0 || coin > 100);
...
// while((coin-0.10)>0)
while((coin - 10) > 0)
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
2

Floating point numbers cannot represent some fractions such as 0.1, 0.05 and 0.01 exactly. Even the sum in coins is not represented exactly, unless it is 0.75, 0.5 or 0.25. When you subtract these values, very small errors accumulate and cause comparisons to produce unexpected results.

You should either carefully convert the sum as an integral number of cents or allow for imprecision in your tests.

Furthermore, your tests are incorrect: for example while ((coin - 0.25) > 0) should be while ((coin - 0.25) >= 0)

Here is a modified version for the first approach:

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

int main(void) {
    float coin;
    int cents;
    int count;

    do {
        coin = get_float("enter the owed change?");
        printf("\n");
    } while (coin <= 0.00 || coin > 1.00);

    cents = roundf(coin * 100);

    count = 0;
    while (cents >= 25) {
        counts -= 25;
        count++;
    }
    while (cents >= 10) {
        cents -= 10;
        count++;
    }
    while (cents >= 5) {
        cents -= 5;
        count++;
    }
    while (cents >= 1) {
        cents -= 1;
        count++;
    }
    printf("%d coins\n", count);
    return 0;
}

This can be simplified into:

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

int main(void) {
    float coin;
    int cents;
    int count;

    do {
        coin = get_float("enter the owed change?");
        printf("\n");
    } while (coin <= 0.00 || coin > 1.00);

    cents = round(coin * 100);

    count = cents / 25;
    cents %= 25;
    count += cents / 10;
    cents %= 10;
    count += cents / 5;
    cents %= 5;
    count += cents;

    printf("%d coins\n", count);
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 1
    Advanced ideas: Note an advantage to `round(some_float * 100.0)` over `cents = round(some_float * 100)`. The first product uses `double` math and with the typical wider `double`, the product is exact. With `some_float * 100` the math may be `float` and perform a rounding _before_ calling `round()` - (significant in edge cases). 2) With `round(some_float * 100)`, might as well use `roundf(some_float * 100)` - no great need for `double` functions with a `float` argument. 3) consider `lround()` or `lroundf()` when saving to integers. – chux - Reinstate Monica Jan 06 '19 at 23:32