user8287021 -3 years ago 116

C Question

Having trouble with float / int calculations for a program designed to convert a dollar value input into its possible constituent parts. For example, if you enter $ 1234.56, the program will output "1 $1000 bill, 2 $100 bills, 1 $20 bill, 1 $10 bill, 4 $4 dollar bills, 2 Quarters, 1 Nickel, and 1 cent."

The biggest issue comes up with calculating pennies. If the user inputs $ .03, the output will vary (at times, I get 3 cents; other times, I get 2 cents). I think I have solved the issue for now, but I would like to understand why I solved it and more importantly I'd like to address the underlying issue: somewhere along the calculation stream, the compiler appears to "shave off" value (e.g. .01 becomes .009999). Is it because I'm performing a recursive calculation on the same variable, namely "amount"? Is there a cleaner way to do what I am trying to do here? (I'm limited to switch / if selection statements, no use of functions, and no use of arrays.)

Link to full code here.

`#include <stdio.h>`

int main(){

float amount, bill_quarter_f, bill_dime_f, bill_nickel_f, bill_penny_f;

int bill_quarter, bill_dime, bill_nickel, bill_penny;

printf("Ex 5.15: Translating Decimal Dollar into Coins\n");

printf("==============================================\n\n");

printf("Enter your amount (e.g .98): $ ");

scanf("%f", &amount);

/************************************/

/* Calculation for greater than MAX */

/************************************/

if (amount >= 1)

printf("\nYou have too much money!\n\n");

/************************************/

/* Calculation for Coins */

/************************************/

else if(amount < 1 && amount > 0){

bill_quarter = amount / .25;

bill_quarter_f = amount / .25;

amount = ((bill_quarter_f - bill_quarter) * .25);

(bill_quarter >= 1 && bill_quarter < 4) ? (printf("You have %d quarters\n", bill_quarter)) : (printf(""));

bill_dime = amount / .10;

bill_dime_f = amount / .10;

amount = (bill_dime_f - bill_dime) * .10;

(bill_dime >= 1 && bill_dime <= 2) ? (printf("You have %d dimes\n", bill_dime)) : (printf(""));

bill_nickel = amount / .05;

bill_nickel_f = amount / .05;

amount = (bill_nickel_f - bill_nickel) * .05;

(bill_nickel >= 1 && bill_nickel < 2) ? (printf("You have %d nickel\n", bill_nickel)) : (printf(""));

bill_penny = amount / .01;

bill_penny_f = amount / .01;

amount = (bill_penny_f - bill_penny) * .01;

(bill_penny_f > 0 && bill_penny_f < 5) ? (printf("You have %.0f pennies\n", bill_penny_f)) : (printf(""));

}

else if (amount == 0)

printf("You have no money!\n");

else

printf("You are in debt!\n");

return 0;

}

Recommended for you: Get network issues from **WhatsUp Gold**. **Not end users.**

Answer Source

Using binary floating-point for financial code has various pitfalls. OP's code exhibits some of those. Without addressing other other ways to represent money (each with their strengths and weaknesses), this answer presents ways to improve `double`

usage with money as it applies to OP's code.

- Inexact representation of money

Recall a binary64 `double`

can typically *exactly* represent about 2^{64} different numbers. `0.10`

is *not* one of them. So the following quotient will often result in a non-whole-number.

```
float amount;
...
amount / .10;
```

Assigning the quotient to an `int`

results in a truncated value. Had the `quotient`

been 1.9999..., `bill_dime`

would take the value of 1.

```
int bill_dime;
...
bill_dime = amount / .10;
```

- No control over input that is not an exact multiple of 0.01.

What to do with user input like `"0.125"`

--> `amount = 0.125`

?

`0.125`

can be exactly represented as `double`

, so there is no rounding issue on input. Yet code does not address how to round such a value or what to do with fraction of 0.01.

- No control over inputing rounded values.

What to do with user input like `"0.10"`

--> that value can not be exactly represented? So a nearby `amount = 0.10f`

results.

`value`

takes on a `float`

value `0.01f`

that is *near* 0.01 and may differ from a `double`

`0.01`

. This difference may result in an unexpected result from `amount / .10;`

. Mixing `double`

and `float`

contributed to this problem.

For financial code employing FP, do not use `float`

- far too many issues.

For OP's learner usage of FP and financial code, recommend to convert the FP input to integers for change computation. As the conversion to `long`

below certainly does not overflow, that concern of OF can be set aside.

```
printf("Enter your amount (e.g .98): $ ");
double amount;
if (scanf("%lf", &amount) != 1) Handle_NonNumericInput();
if (amount >= 1.0 || amount < 0.0)
printf("\nYou have too much/too little money!\n\n");
```

Now move to integers

```
else {
// round ... to the nearest integer value, rounding halfway cases away from zero,
long cents = lround(amount * 100.0);
// 0 <= cents <= 100
// Need to decide how to handle cents == 0 or cents == 100 here.
bill_quarter = cents / 25;
cents %= 25;
if (bill_quarter) {
printf("You have %d quarters\n", bill_quarter);
}
bill_dime = cents / 10;
cents %= cents % 10;
if (bill_dime) {
printf("You have %d dimes\n", bill_dime);
}
```

Minor

```
// "You have %d nickel"
"You have %d nickels"
```

Recommended from our users: **Dynamic Network Monitoring from WhatsUp Gold from IPSwitch**. ** Free Download**

Latest added