0

Please find the question context as follows:

Write a program that takes in a floating point value representing an amount, for example 2.8 indicating 2 dollars and 80 cents. The program should then display the minimum number of coins required to repay the amount in coins. Assume that the user enters a value above 0 and below 10.

#include <stdio.h>

int main(void) {
    double amt;
    printf("Enter amount:");
    scanf("%lf", &amt);

    int amt_cents;
    amt_cents = amt * 100;

    int dollar_1;
    dollar_1 = amt_cents / 100;
    amt_cents = amt_cents - (dollar_1 * 100);

    int cents_50;
    cents_50 = amt_cents / 50;
    amt_cents = amt_cents - (cents_50 * 50);

    int cents_20;
    cents_20 = amt_cents / 20;
    amt_cents = amt_cents - (cents_20 * 20);

    int cents_10;
    cents_10 = amt_cents / 10;
    amt_cents = amt_cents - (cents_10 * 10);

    int cents_05;
    cents_05 = amt_cents / 5;
    amt_cents = amt_cents - (cents_05 * 5);

    int cents_01;
    cents_01 = amt_cents / 1;
    amt_cents = amt_cents - (cents_01 * 1);

    if (dollar_1 != 0) {
        printf("Number of 1$: %d\n", dollar_1);
    }
    if (cents_50 != 0) {
        printf("Number of 50c: %d\n", cents_50);
    }
    if (cents_20 != 0) {
        printf("Number of 20c: %d\n", cents_20);
    }
    if (cents_10 != 0) {
        printf("Number of 10c: %d\n", cents_10);
    }
    if (cents_05 != 0) {
        printf("Number of 5c: %d\n", cents_05);
    }
    if (cents_01 != 0) {
        printf("Number of 1c: %d\n", cents_01);
    }
}

Output:

Enter amount:1.1 Number of 1$: 1 Number of 10c: 1

Enter amount:2.1 Number of 1$: 2 Number of 10c: 1

Enter amount:3.1 Number of 1$: 3 Number of 10c: 1

Enter amount:4.1 Number of 1$: 4 Number of 5c: 1 Number of 1c: 4

Enter amount:5.1 Number of 1$: 5 Number of 5c: 1 Number of 1c: 4

Enter amount:6.1 Number of 1$: 6 Number of 10c: 1

Question: Why does the values for 4.1 and 5.1 work differently compared to all other values within 0 - 10? By calculating manually down the code, it appears that 4.1 and 5.1 should be consistent with all other cases with producing only a value of 1 for 10c, but that is not the case when the programme is executed.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
jaydxn1
  • 47
  • 2
  • 1
    The closest double value to 4.1 and 5.1 is slightly smaller, therefore when treating as integer rounding down to 409 and 509 cents. – mkrieger1 Aug 26 '20 at 15:53
  • 1
    @mkrieger1: That's a lot to sift through to try and figure out how to fix this particular program. – Robert Harvey Aug 26 '20 at 15:55
  • 1
    If you want exact dollars and cents, try parsing the dollar amount and the cent amount as separate integers rather than as a floating point value. – Iguananaut Aug 26 '20 at 15:55
  • 1
    This illustrates why using floating point for money isn't such a good idea. – Fred Larson Aug 26 '20 at 16:03
  • 2
    Round. `amt_cents = amt * 100;` --> `amt_cents = lround(amt * 100.0);` – chux - Reinstate Monica Aug 26 '20 at 16:12
  • @RobertHarvey True, but after reading it, they’ll likely not do the same mistake again. – mkrieger1 Aug 26 '20 at 17:21
  • Bankers don't use floating point to represent amounts/balances [because of the roundoff]. That's why [old] IBM mainframes had "packed decimal" math instructions. Better to use `int` to represent cents [vs. fractional dollars]. Consider using scaled int math (e.g.): `int getamt(void) { char *cur; char buf[100]; int dol; int cent = 0; scanf("%s",buf); dol = strtol(buf,&cur,10); if (*cur == '.') cent = strtol(cur + 1,&cur,10); return cent + (dol * 100); } void prtamt(int cent) { printf("%d.%2.2d",cent / 100,cent % 100); }` – Craig Estey Aug 26 '20 at 17:44

1 Answers1

1

Why does the values for 4.1 and 5.1 work differently compared to all other values within 0 - 10?

Because floating point numbers don't always represent values exactly. Look at this code:

double amt;
printf("Enter amount:");
scanf("%lf", &amt);

int amt_cents;
amt_cents = amt * 100;

If you set a breakpoint after that last line and check the value of amt_cents you'll likely find that it's 409 instead of the 410 that you expect, because amt is something like 4.09999999....

You'll want to round the number to the nearest integer instead of just taking the integer part, an an easy way to do that is to add 0.5 to the value and then truncate:

amt_cents = amt * 100.0 + 0.5;
Caleb
  • 124,013
  • 19
  • 183
  • 272
  • I think `amt * 100` is fine. Because `amt` is a `double`, `100` should be converted to `double` as well. The `+ 0.5` part is the important bit. – Fred Larson Aug 26 '20 at 16:06
  • @FredLarson I'm sure you're right -- 100 should be promoted to double rather than `amt` being demoted to int. My habit is to avoid mixing types as much as possible to avoid questions like that. I'll edit. – Caleb Aug 26 '20 at 16:12
  • There are many good round functions that handle rounding better than truncation after `+ 0.5` which fails corners cases. I recommend [`lround()`.](https://en.cppreference.com/w/c/numeric/math/round) – chux - Reinstate Monica Aug 26 '20 at 16:14