
Нужно рассчитать комиссию 0.1% от суммы 123.45 ₽ и вычесть её.
Правильный ответ: BigDecimal amountBD = BigDecimal.valueOf(amount); BigDecimal commission = amountBD.multiply(BigDecimal.valueOf(0.001)).setScale(2, RoundingMode.HALF_EVEN);
Почему это так и в чем заключаются ловушки остальных вариантов:
Почему A — плохо (Ошибка точности)
Использование double для денег — это грех в финтехе.
double использует двоичную арифметику с плавающей точкой (IEEE 754). Число 0.1 или 123.45 не могут быть представлены в двоичной системе абсолютно точно.
При умножении 123.45 * 0.001 вы можете получить что-то вроде 0.12345000000000001. При конвертации обратно в копейки (целые числа) это приведет к ошибке на 1 копейку. В масштабах банка это миллионные убытки.
Почему B — самая опасная ловушка (Конструктор BigDecimal)
Многие джуны знают, что для денег нужен BigDecimal, и выбирают этот вариант. Но это ошибка.
Конструктор new BigDecimal(double) берет точное двоичное представление числа.
Если вы напишете new BigDecimal(123.45), вы получите не 123.45, а:
123.4500000000000028421709430404007434844970703125
Вы просто переносите ошибку double внутрь BigDecimal.
Почему C — неполноценно (Отсутствие округления)
BigDecimal.valueOf(double) — это правильно, так как этот метод сначала конвертирует число в строку (Double.toString()), а потом создает BigDecimal. Вы получите чистые 123.45.
Но: В варианте C нет округления.
Результат умножения 123.45 * 0.001 будет 0.12345.
В банковской системе нельзя хранить 0.12345 рубля. Нужно округлить до 2 знаков (копеек). Без setScale вы получите ошибку при попытке сохранить это в БД или при дальнейших расчетах.
Почему D — идеально
BigDecimal.valueOf(amount): Безопасная конвертация из double (через строку).
multiply: Точное вычисление.
setScale(2, RoundingMode.HALF_EVEN): Самый важный пункт.
Мы явно указываем, что нам нужно 2 знака после запятой (валюта).
RoundingMode.HALF_EVEN (Банковское округление) — это стандарт в финтехе. Оно минимизирует статистическую ошибку при массовых вычислениях (округляет к ближайшему четному числу, если цифра ровно посередине, например, 0.5).
