Как считать деньги в Java
Короткий ответ
double хранит дробные числа приблизительно, поэтому для денег используют BigDecimal:
void main() {
IO.println(0.1 + 0.2);
IO.println(new BigDecimal("0.10").add(new BigDecimal("0.20")));
}Результат:
0.30000000000000004
0.30Арифметика
Операторы + и * с BigDecimal не работают — нужны методы. Каждый метод возвращает новое число:
void main() {
var price = new BigDecimal("19.99");
var quantity = BigDecimal.valueOf(3);
var discount = new BigDecimal("5.00");
var total = price.multiply(quantity).subtract(discount);
IO.println(total);
}Результат:
54.97Налог с округлением
После умножения на процент знаков становится больше — округлите до копеек:
void main() {
var net = new BigDecimal("49.99");
var vat = net.multiply(new BigDecimal("0.19"));
IO.println(vat);
IO.println(vat.setScale(2, RoundingMode.HALF_UP));
}Результат:
9.4981
9.50Деление
При делении укажите масштаб и правило округления, иначе бесконечная дробь вызовет исключение:
void main() {
var bill = new BigDecimal("100.00");
var share = bill.divide(BigDecimal.valueOf(3), 2, RoundingMode.HALF_UP);
IO.println(share);
}Результат:
33.33Сравнение
equals() учитывает количество знаков после запятой, а compareTo() — только значение:
void main() {
var a = new BigDecimal("2.0");
var b = new BigDecimal("2.00");
IO.println(a.equals(b));
IO.println(a.compareTo(b) == 0);
}Результат:
false
trueЧастая ошибка
Создавать BigDecimal из double. Неточность double переходит в BigDecimal целиком:
void main() {
IO.println(new BigDecimal(0.1));
IO.println(new BigDecimal("0.1"));
IO.println(BigDecimal.valueOf(0.1));
}Результат:
0.1000000000000000055511151231257827021181583404541015625
0.1
0.1Создавайте из строки или через BigDecimal.valueOf().
Функции из этого ответа
- BigDecimal — Точное десятичное число — для денег и расчётов, где недопустимы ошибки округления double.