CURRENCY - Round double value ONLY if it has more than 2 decimal places

Dylan :

I'm trying to split a bill and need to calculate how much each person would owe if the bill was split in even amounts. I know one amount will be different than the rest to account for the lost cents.

Assume 3 people try to split a bill for 200. 200 / 3 is 66.6666666667. What I planned on doing was charging the 2 first people 66.67 and the last gets lucky with the 66.66 bill.

At the minute, I have this so far:

private String calculateAmountToPay(String noOfParticipants, String owed) {
    double amountOwed = Double.parseDouble(owed);
    int noOfMembers = Integer.parseInt(noOfParticipants);
    DecimalFormat amountFormat = new DecimalFormat("#.##");
    amountFormat.setRoundingMode(RoundingMode.CEILING);
    return amountFormat.format((amountOwed/(double)noOfMembers) / 100);
  }

But this always will return 66.67. Is there a way that I can get it to only round up if there is a number greater than 2 decimal places, if not, it stays at 66.66 for example?

Maybe I'm approaching this the wrong way. I know currency can be finicky to deal with.

Bohemian :

Before even thinking about arithmetic, you need to know that double is not an appropriate data type for use with currency, because it’s imprecise. So, stop using a floating point type (eg double) as the data type for the quantity of dollars and start using a precise type (eg long) as the data type for the quantity of cents.

The steps then to do the calculation would be to immediately convert everything, with rounding, to cents:

double amountOwed = ...;
int noOfMembers = ...;
long centsOwed = Math.round(amountOwed * 100);
long portionCents = Math.round(amountOwed * 100 / noOfMembers);
long errorCents = portionCents * noOfMembers - centsOwed;

Here’s one way to deal with the error:

long lastPortionCents = portionCents - errorCents;

But it’s possible that the error is more than 1 cent, so a better solution would be to spread the error out evenly by subtracting (or adding if the error is negative) 1 cent from the first (or last, or randomly chosen) errorCents diners.

The rest of the solution is then about rending the above, which I leave to the reader.

As a side note, using cents is how banks transmit amounts (at least for EFTPOS anyway).


Regarding basic software design, I would create a separate method that accepts integer cents and people count as its parameters and returns an array of the "split" amounts. Doing this will not only make your code easier to read, but it will compartmentaise the arithmetic operation and thus enable lots of simple tests to more easily be written, so you can know you have all the edge cases that you can think of covered.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=77315&siteId=1