Вопрос с собеседования · Java

Что выведет System.out.println(0.1 + 0.2 == 0.3) и что брать для денег?

JuniorОсновы языка
Коротко

false: 0.1 непредставимо точно в двоичной плавающей точке (IEEE 754), сумма даёт 0.30000000000000004. Для денег — BigDecimal из строки (new BigDecimal("0.1")) или копейки в long.

  • double сравнивают с допуском: Math.abs(a − b) < eps
  • new BigDecimal(0.1) уже содержит погрешность — BigDecimal.valueOf или строка
  • BigDecimal.equals учитывает масштаб: 2.0 ≠ 2.00, сравнивать compareTo

А ещё Округление — явно: setScale(2, RoundingMode.HALF_EVEN)

Попробуйте сами

Число изнутри: дополнительный код и плавающая точка

Подробно

Дробные числа хранятся в двоичной плавающей точке, где 0.1 непредставимо точно, поэтому сумма даёт 0.30000000000000004. Сравнивать double на равенство нельзя — сравнивают с допуском (|a-b| < eps). Для денег берут BigDecimal и создают его из строки (new BigDecimal("0.1")), а не из double, иначе погрешность переедет внутрь.

Что хотят услышать

  • Причина погрешности.
  • BigDecimal и правильное создание.
  • Сравнение double и BigDecimal.

Частые ошибки

  • Хранить деньги в double/float.
  • Создавать BigDecimal из double-литерала вместо строки.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✗true — компилятор округлит; для денег подойдёт float
  • ✓false — погрешность IEEE 754; для денег берут BigDecimal
  • ✗true — double точен для таких чисел; деньги тоже храни в double
  • ✗Ошибка компиляции: double нельзя сравнивать через ==

Что спросят дальше

  • Почему new BigDecimal(0.1) хуже new BigDecimal("0.1")?
  • Как корректно сравнить два double?

Разбор темы

Связанные вопросы

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования