I have a input to a method that represents an amount of money, a total price of X items.
This can be an amount under a number of currencies and is represented by a double
.
Question: I want to break this amount into the price for each of the X items. Considering that the amount itself is a double
my concern is that if I simply do: amount/X
I could get a number that number*X
does not give me the amount
exactly due to e.g. rounding. How can I do this correctly?
Note: Please give me help taking for granted that I can not change the amount
to be something other than a double

- 18,826
- 34
- 135
- 254
-
You can convert the double to a `BigDecimal` and do the calculations with that. – Kayaman Aug 25 '15 at 05:49
-
@Kayaman: How do you think that will help? – tmyklebu Aug 25 '15 at 13:53
-
@tmyklebu Well it'll allow you to do precise calculations. However if other parts expect a `double`, it just means that the code was broken to begin with. If you're dealing with money, you need to work with `BigDecimal` until you pretty print the result for a user (who most likely doesn't want to see values such as `10.000000000256`). – Kayaman Aug 25 '15 at 14:14
-
@Kayaman: BigDecimal can't represent rationals exactly. It's still a floating-point format, and the pigeonhole principle still applies---there is still a BigDecimal f such that (1/f)*f != 1. ("If you're dealing with money, you need to work with BigDecimal" is totally false, by the way; plenty of financial applications get by just fine using doubles.) – tmyklebu Aug 25 '15 at 14:31
4 Answers
As you already mentioned, this is not possible in every case. Usually, when the total price is really the product of the single item price and a quantity, the resulting double will have enough precision to do this calculation. But generally you have to store both prices.
I implemented a whole ERP, and we also have a feature where the user can specify the total line amount directly, maybe to round the sum after discussing with a customer. And this makes it possible to sell 7 items for 1000$. Then there is no way to create a precise representation of a price for a single item. And therefore we also store the item price rounded (cut after 4 digits).
To come back to your answer: Depending on context you will need the total and single item amount later anyway, so just store both.

- 27,718
- 20
- 89
- 133
-
I don't have an issue keeping both. But showing a price in 4 digits (because only this way we can multiply to get back to the correct amount), was that an issue to your customer? I don't remember ever seeing prices with 4 digits after decimal – Jim Aug 25 '15 at 06:21
-
At least in my country prices for fuel are given in higher precision that useful. A litre costs e.g. 1,299EUR, and are rounded after multiplying with the amount of fuel loaded. This is obviously a scam, because 1,30 is the effective price. Nonetheless, a single item price can always have higher precision that the line item amount. – Daniel Aug 27 '15 at 09:25
You can use BigDecimal
class:
double a=456.6556756;
BigDecimal amount=BigDecimal.valueOf(a);
BigDecimal priceOfEachItem=amount.divide(BigDecimal.valueOf(8));
BigDecimal amountAgain=priceOfEachItem.multiply(BigDecimal.valueOf(8));
System.out.println(amountAgain.doubleValue());
Output:456.6556756
As you can see you can get the exact original amount

- 1,048
- 1
- 6
- 16
-
Yes but what will happen if I convert the result back to double to pass to other functions? – Jim Aug 25 '15 at 06:22
-
@Jim You will have no problem at all. You can retrive the double value as: double value=amountAgain.doubleValue(); and pass it to other functions – hermit Aug 25 '15 at 06:26
-
But if you want a complete precision accuracy then you have to use BigDecimal in other functions too.. – hermit Aug 25 '15 at 06:28
-
This division will only work for an exact multiple. What if the per unit price is not a cent. BTW you can't have `$456.6556756` – Peter Lawrey Aug 25 '15 at 07:23
-
The question asks for exact multiple as far as I can understand. :) I only wanted to show that BigDecimal preserves the precision with complete accuracy. Did not think about the currency aspect :) – hermit Aug 25 '15 at 07:28
You can do this by taking the single item price as double value which won't round off the value(Yes,you may limit the number of digits after decimal).
double totalPrice = 500.33;
int totalItems = 6;
double singleItemPrice = totalPrice/totalItems;
System.out.println("Single Item Price = " + singleItemPrice);
System.out.println("Total Price = " + (singleItemPrice * totalItems));
DecimalFormat df = new DecimalFormat("#.##");
Double formatted = Double.parseDouble(df.format(singleItemPrice * totalItems));
System.out.println("Formatted Value = "formatted);
Output:
Single Item Price = 83.38833333333334
Total Price = 500.33000000000004
Formatted Value = 500.33
Or use BigDecimal
as mentioned by someone else(but maybe the above will have more precision, let us know about that):
import java.math.BigDecimal;
BigDecimal premium = BigDecimal.valueOf(1586.6d);
BigDecimal netToCompany = BigDecimal.valueOf(708.75d);
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);
Output:
877.85 = 1586.6 - 708.75
Hope this was what you were looking for.
-
Yes but what will happen if I convert the result back to double to pass to other functions? – Jim Aug 25 '15 at 06:23
You can use Math.round for rounding. The problem you have is that you don't know what rounding for you amount/X
you need. This is a problem whether you use double
or BigDecimal
You can do this
public static double round2(double d) {
if (d < -Long.MAX_VALUE / 100 || d > Long.MAX_VALUE / 100)
return d;
return Math.round(d * 100) / 100.0;
}
public static void main(String[] args) throws IOException {
double amount = 1000.00;
int units = 9;
System.out.println("amount: " + amount );
System.out.println("units: " + units);
double perUnit = amount / units;
double amount2 = round2(perUnit * units);
System.out.println("perUnit: " + perUnit);
System.out.println("amount2: " + amount2);
}
prints
amount: 1000.0
units: 9
perUnit: 111.11111111111111
amount2: 1000.0

- 525,659
- 79
- 751
- 1,130