Reputation: 13
I'm a beginner programmer and I am writing a change machine program. I almost have it down, but for some reason, Math.floor()
give a result of 0 instead of the intended number.
I've tried using Math.round()
instead, but I'm fairly sure it should be Math.floor()
for most accurate results.
public void calculateChange(){
changeTotal = moneyGiven - total;
wholeDollars = Math.floor(changeTotal);
quarters = Math.floor((changeTotal - wholeDollars)/.25);
dimes = Math.floor(((changeTotal - wholeDollars) - quarters * .25)/.1);
nickles = Math.floor(((changeTotal - wholeDollars) - quarters * .25 - dimes * 0.1)/.05);
pennies = Math.floor(((changeTotal - wholeDollars) - quarters * .25 - dimes * 0.1 - nickles * .05)/ .01);
}
For example, when I run the method below with the input of $5 as cash given, and $1.29 as the transaction total, I get change of 3 dollars, 2 quarters, 2 dimes, 0 nickles, and 0 pennies.
The penny value should be 1. It seems to only have this issue if the result for any given expression should be 1.
Upvotes: 1
Views: 410
Reputation: 23634
I would re-think the solution a bit here. There's nothing too wrong with your approach, but thinking about this using integer math rather than floating point will simplify the whole operation. You also can use intermediate variables to avoid repeating the same operations over and over again.
int dollars = (int) (changeTotal);
int cents = (int) (changeTotal * 100) % 100;
int quarters = cents / 25;
cents = cents % 25;
int dimes = cents / 10;
cents = cents % 10;
int nickels = cents / 5;
cents = cents % 5;
int pennies = cents;
Upvotes: 1
Reputation: 1502
You seem to have declared your variables as floating point numbers and are getting rounding errors as a result.
I'll be taking your example with moneyGiven = 5.00
dollars and total = 1.29
dollars.
While the value of the expression (changeTotal - wholeDollars)
is 0.71
and the value of quarters * .25
is 0.5
, subtracting them in the expressiong (changeTotal - wholeDollars) - quarters * .25
actually results in 0.20999999999999996
due to the way floating point numbers are represented in memory and math operations.
In the end, the result of the entire expression ((changeTotal - wholeDollars) - quarters * .25 - dimes * 0.1 - nickles * .05)/ .01
is 0.9999999999999953
, which then gets floored to 0
.
The kind of operations you perform also have an influence. If I change your divisions into multiplications of the inverse like the following, I actually get 1.0000038146972645
as result of the final expression, which is then floored to 1
:
public static void calculateChange(double moneyGiven, double total) {
double changeTotal = moneyGiven - total;
double wholeDollars = Math.floor(changeTotal);
double quarters = Math.floor((changeTotal - wholeDollars) * 4.0);
double dimes = Math.floor(((changeTotal - wholeDollars) - quarters / 4.0) * 10);
double nickles = Math.floor(((changeTotal - wholeDollars) - quarters / 4.0 - dimes / 10.0) * 20.0);
double pennies = Math.floor(((changeTotal - wholeDollars) - quarters / 4.0 - dimes / 10.0 - nickles / 20.0) * 100);
System.out.println(wholeDollars + " " + quarters + " " + dimes + " " + nickles + " " + pennies);
}
Even storing the intermediate results as integers does not fully negate the issue, because your total
and moneyGiven
are still floating point values. By changing their type from double
to float
, you mitigate the issue somewhat by having less precision, which may result in more favorable rounding. But it does not reliably solve the underlying problem.
Serious financial programs should never use primitive floating point datatypes to do any calculations because of rounding errors. Instead, they use a special type called BigDecimal
.
Upvotes: 1
Reputation: 700
First of all, your code does not show any of the data types of your variables. This makes it difficult for me to pinpoint the exact cause of the issue here.
That aside, your variables need to be cast as integers. I've made edits to the structure of your method; moneyGiven
and total
are now float parameters.
Calling the method as calculateChange(5, 1.29f)
gave me the correct output of 3 2 2 0 1
.
public static void calculateChange(float moneyGiven, float total) {
float changeTotal = moneyGiven - total;
int wholeDollars = (int) Math.floor(changeTotal);
int quarters = (int) Math.floor((changeTotal - wholeDollars)/.25);
int dimes = (int) Math.floor(((changeTotal - wholeDollars) - quarters * .25)/.1);
int nickles = (int) Math.floor(((changeTotal - wholeDollars) - quarters * .25 - dimes * 0.1)/.05);
int pennies = (int) Math.floor(((changeTotal - wholeDollars) - quarters * .25 - dimes * 0.1 - nickles * .05)/.01);
System.out.println(wholeDollars + " " + quarters + " " + dimes + " " + nickles + " " + pennies);
}
Upvotes: 1