1

This code is supposed to take the amount due for an item and the amount paid. Then find the change in coins and dollars. When ever I put due: 41.35 and received: 50.00, I get 8 dollars, 2 quarters, 1, dime, 0 nickels, 4 pennies. In reality, it should be 8 dollars, 2 quarters, 1, dime, 1 nickel, 0 pennies.

import java.util.Scanner;
public class Cashier {
    private double amountDue;
    private double amountReceived;
    private int dollars = 0;
    private int quarters = 0;
    private int dimes = 0;
    private int nickels = 0;
    private int pennies = 0;
    private double toConvert;

    public Cashier(double due, double received){
        amountDue = due;
        amountReceived = received;
        toConvert = received - due;
    }
    public int getDollars(){
        dollars = (int)toConvert;
        toConvert -= dollars;
        return dollars;
    }
    public int getQuarters(){
        quarters = (int)(toConvert/.25);
        toConvert -= (.25 * quarters);
        return quarters;
    }
    public int getDimes(){
        dimes = (int)(toConvert/0.1);
        toConvert -= (.1 * dimes);
        return dimes;
    }
    public int getNickels(){
        nickels = (int)(toConvert/0.05);
        toConvert -= (0.05 * nickels);
        return nickels;
    }
    public int getPennies(){
        pennies = (int)(toConvert/0.01);
        toConvert -= (0.01 * pennies);
        return pennies;
    }
    public static void main(String[] args){
        Scanner ask = new Scanner(System.in);
        System.out.print("Enter Amount Due: ");
        double amtDue = ask.nextDouble();
        System.out.print("Enter Amount Received: ");
        double amtReceived = ask.nextDouble();

        Cashier one = new Cashier(amtDue, amtReceived);
        System.out.println("Dollars = " + one.getDollars());
        System.out.println("Quarters = " + one.getQuarters());
        System.out.println("Dimes = " + one.getDimes());
        System.out.println("Nickels = " + one.getNickels());
        System.out.println("Pennies = " + one.getPennies());

    }

}
Bob Chan
  • 11
  • 1
  • 1
    You are running into [floating point rounding errors](https://stackoverflow.com/q/588004/1270789). The simplest way would be to immediately convert the dollar `amntDue` into cents and store the result in an integer - `int centsDue = (int) Math.round(amntDue * 100);` - and use that throughout the code. – Ken Y-N Oct 19 '20 at 02:05
  • In concrete terms, if you run this case under a debugger, by the time you get to `getNickels()` the value of `toConvert` is 0.04999999999999857. So `toConvert/0.05` is 0.9999999999999715, which when truncated to an `int` is zero. – tgdavies Oct 19 '20 at 02:14

3 Answers3

1

Interesting problem you ran into here. Here's how I went about figuring it out. First thing I did was try printing the amount of change left to break down after you ran each function. I changed the main function to look like this:

NOTE: I had to change toConvert to static to use it in the main function

public static void main(String[] args) {
    Scanner ask = new Scanner(System.in);
    System.out.print("Enter Amount Due: ");
    double amtDue = ask.nextDouble();
    System.out.print("Enter Amount Received: ");
    double amtReceived = ask.nextDouble();

    TestA one = new TestA(amtDue, amtReceived);
    System.out.println("change due: " + toConvert);
    System.out.println("Dollars = " + one.getDollars());
    System.out.println("change due: " + toConvert);
    System.out.println("Quarters = " + one.getQuarters());
    System.out.println("change due: " + toConvert);
    System.out.println("Dimes = " + one.getDimes());
    System.out.println("change due: " + toConvert);
    System.out.println("Nickels = " + one.getNickels());
    System.out.println("change due: " + toConvert);
    System.out.println("Pennies = " + one.getPennies());
    System.out.println("change due: " + toConvert);
}

The output looked like this:

Enter Amount Due: 41.35
Enter Amount Received: 50.00
change: 8.649999999999999
Dollars = 8
change: 0.6499999999999986
Quarters = 2
change: 0.14999999999999858
Dimes = 1
change: 0.04999999999999857
Nickels = 0
change: 0.04999999999999857
Pennies = 4
change: 0.009999999999998573

This told me that the issue was in rounding your double values. The change should have been 8.65 in the first part if the program was running correctly. This has to do with how double values are stored on the hardware and its a pretty confusing topic(to me, at least).

Change the values to float instead of double and it'll work fine. There's info out there on this website and others about rounding double values and there are ways around it like formatting to x number of decimals and rounding and such but think changing it to float is an easier avenue.

CodingNinja
  • 245
  • 1
  • 12
0

You need to designate the input in terms of cents, which is the smallest form of currency you can accept. Otherwise, for a charge of 70¢, given 3 quarters, your code would try to it convert it to dollars.

The code is very simple, and can be written as a single recursive function without the need for dozens of special methods. I won't do it for you, but the following should give you a very good idea.

865 / 100 = 8
65 / 25 = 2
15 / 10 = 1
5 / 5 = 1
0 / 1 = 0
Abhijit Sarkar
  • 21,927
  • 20
  • 110
  • 219
  • What do you mean by "for a charge of 70¢, given 3 quarters, your code would try to it convert it to dollars"? The original code handles that particular case correctly. – tgdavies Oct 19 '20 at 02:17
  • @tgtdavies It doesn’t. What happens if you input 3? Is 3 equal to $3, 75c or 3c? There needs to be a way to indicate the denominations, just like we do for dates in ISO-8601 format. – Abhijit Sarkar Oct 19 '20 at 02:41
  • The original code uses dollars. If you give it 0.7 and 0.75 is correctly gives change of 1 nickel. – tgdavies Oct 19 '20 at 03:06
  • So when does this floating error occur? Every time you do arithmetic operations with two doubles? When I do something like System.out.println(5.6-1.1);, it gives 4.5. Then why is it that my problem goes to 8.64999999999? – Bob Chan Oct 19 '20 at 03:29
  • @BobChan Someone already provided a link to the [most popular SO post on fp math](https://stackoverflow.com/q/588004/839733). Read it. – Abhijit Sarkar Oct 19 '20 at 03:30
-1

After this step : toConvert = received - due; The toConvert amount turns to 8.649999999999999 This requires an additional step to the round of decimal to two places so the amount turns 8.65 change your Cashier funtion to this:

public Cashier(double due, double received){
    amountDue = due;
    amountReceived = received;
    double num = received - due;
    toConvert = Math.round(num * 100.0) / 100.0;
    System.out.println(toConvert);
}

This solution works temporary while working with a double. But converting figure to cents and using arithmetic solve is the right way.

proxyMac
  • 9
  • 2
  • The rounding problems can happen in any of the coin conversion steps. As others have said, converting the figures to cents and using integer arithmetic is the correct solution. – tgdavies Oct 19 '20 at 03:00
  • Your solution to round the toConvert to 8.65 fixed the problem. Thank you. So when does this floating error occur? Every time you do arithmetic operations with two doubles? When I do something like System.out.println(5.6-1.1);, it gives 4.5. Then why is it that my problem goes to 8.64999999999? – Bob Chan Oct 19 '20 at 03:27