user3284325
user3284325

Reputation: 1

Why does it keep rounding down to two cents on my java change/cashier program?

I have tried many ways like math.Round and making them doubles and ints but i have no idea why and where it rounds down to 2 cents at the end. When i purchase 32.27 and pay with 36 the answer is 3 dollars 2 quarters 2 dimes 2 cents. here is my code:

import java.util.Scanner;

public class Change {

    public static void main(String[] args) {

        Scanner input = new Scanner(System.in);


        System.out.print("Purchase: ");
        double purchase = input.nextDouble();
        System.out.print("Payment: ");
        double amountGiven = input.nextDouble();

        int remainingAmount = (int) ((amountGiven - purchase) * 100);


        int numOfDollars = remainingAmount / 100;
        remainingAmount = remainingAmount % 100;

        int numOfQuarters = remainingAmount / 25;
        remainingAmount = remainingAmount % 25;

        int numOfDimes = remainingAmount / 10;
        remainingAmount = remainingAmount % 10;

        int numOfPennies = remainingAmount;

        System.out.println("Given $ " + amountGiven + " for a purchase of $ " +
                purchase + " we need " + numOfDollars + " dollars " + numOfQuarters +
                " quarters " + numOfDimes + " dimes " +
                numOfPennies + " cents ");
    }
}

Upvotes: 0

Views: 287

Answers (4)

user177800
user177800

Reputation:

You can't do division that results in remainders on integer types without losing precision

double d1 = 32.27;
double d2 = 36;
int i1 = (int) (d1 * 100);
int i2 = (int) (d2 * 100);
int rad = (int) ((d1 - d2 ) * 100);
int rai = i1 - i2;
double rdd = (double)rai / 100; // <- this is what you are expecting
int ndi = rai / 100;            
//  ^ this is what you are getting 
//  int / int == double which gets silently truncated

System.out.println("i1 = " + i1);
System.out.println("i2 = " + i2);
System.out.println("rad = " + rad);
System.out.println("rai = " + rai);
System.out.println("rdd = " + rdd); // mostly accurate in this case
System.out.println("ndi = " + ndi); // truncated

Ouputs

i1 = 3227
i2 = 3600
rad = -372
rai = -373
rdd = -3.73
ndi = -3

Upvotes: 0

Henry
Henry

Reputation: 43738

This happens, because the amount cannot be represented exactly as a double. When you convert to an int it gets truncated.

The change amount in cents is 372.99999999999955 if you print it with 14 decimals.

Either use BigDecimal or a custom Currency type that only uses Integer or int to do calculations.

Upvotes: 1

Marko Topolnik
Marko Topolnik

Reputation: 200168

If you run this code, you'll see where your problem is:

final double purchase = 32.27;
System.out.println("Purchase: " + new BigDecimal(purchase));
final double diff = 36 - purchase;
System.out.println("Difference: " + new BigDecimal(diff));
System.out.println("Cent difference: " + (int)(100*diff));

The output will be

Purchase: 32.27000000000000312638803734444081783294677734375
Difference: 3.72999999999999687361196265555918216705322265625
Cent difference: 372

So you can see that your trouble starts right off the bat: the decimal value 32.27 is represented by the nearest double value, which is slightly larger. The difference is then slightly less, which after truncation drops a whole cent.

Lesson: don't parse the input into a double, but into a BigDecimal.

Upvotes: 1

jpkroehling
jpkroehling

Reputation: 14061

Calculations of this type should never use primitive types. Always use BigDecimal.

Upvotes: 0

Related Questions