TGViewer
Java: fill the gaps Java: fill the gaps @java_fillthegaps · 12.3K subscribers
Post #408 6.74K
BigDecimal

В этом посте обсудим, зачем нужен этот класс и как не ошибиться при использовании.

Ответ на первый вопрос перед постом — false. Сумма 0.1 и 0.2 равна 0.30000000000000004.

Запустим тот же пример на Python 2.7:
print(0.1 + 0.2)
0.3

Почему python справился с примером, а java — нет? Как писать на java высоконагруженные приложения, если она не может сложить 0.1 и 0.2?😒

Oracle подробно объясняет этот феномен на 80 страницах. Главная проблема в том, как десятичная часть хранится в двоичном формате.

Целые числа записываются через степень двойки однозначно:
9 = 8 + 1 = 2^3 + 2^0 → 1001

Десятичная часть выражается через отрицательную степень двойки. Иногда получается нормально:
0.5 = 2^(-1) → 0.1

Иногда не очень:
0.1 = 2^(-4) + 2^(-5) + 2^(-8) + … →
0.00111101110011001100110011001

Если перевести это обратно в десятичную форму, видно, что хранится там совсем не 0.1, а 0.100000001490116119384765625

С 0.2 похожая ситуация, поэтому результат получается искажённым.

Python 2.7 использует для вычислений ту же систему, но показывает меньше знаков после запятой. Поэтому ответ выглядит нормально. Python 3 выводит больше знаков и результат похож на результат java:
print(0.1 + 0.2)
0.30000000000000004

❓Зачем использовать такую неточную систему?

Если хранить целую и дробную часть одинаково, то для вычислений не нужно дополнительных преобразований. Результат считается быстро, а уровень погрешности на практике низкий. В нашем примере ошибка на 16 разрядов ниже основного значения, в большинстве случаев это ок.

Для точных вычислений используются три основных метода:
🔸Ограниченная точность (limited-precision decimal)
🔸Символьная логика (symbolic calculations)
🔸Длинная арифметика (arbitrary-precision decimal)

BigDecimal использует последний подход. Число 12.345 хранится как пара:
▫️целое значение: 12345
▫️количество десятичных знаков: 3

За счёт этого BigDecimal хранит числа без потери точности. Целая часть хранится либо в переменной int, либо в массиве. Размер числа ограничен только количеством доступной памяти.

Из минусов:
❌ Медленные вычисления
❌ Большой расход памяти
❌ Много промежуточных объектов
❌ Менее выразительный код

Теперь ответ на второй вопрос перед постом:
объекты BigDecimal(0.2) и BigDecimal("0.2") НЕ равны.

В конструктор
BigDecimal(0.2)
передаётся примитив double, в котором вместо 0.2 лежит
0.20000000000000001110223...
Поэтому объект BigDecimal будет хранить это число, а не 0.2

Это самая частая ошибка при работе с BigDecimal. Для чисел с запятой надёжнее передавать в конструктор строку.
  • 🔥 148
  • 👍 55
  • ❤ 17
More from @java_fillthegaps
  1. Apr 30, 2026Get Your Hands Dirty on Clean Architecture: отзыв на книгу Когда я подняла тему чистой арх…
  2. Apr 27, 2026​Clean Architecture: отзыв на книгу Наконец-то дочитала книгу Clean Architecture Роберта М…
  3. Mar 4, 2026Как переиспользовать контекст в интеграционных тестах Сегодня расскажу базовый минимум для…
  4. Mar 4, 2026Post #660
  5. Mar 4, 2026Тестовый контекст поднимается 2 минуты. У нас 4 класса с интеграционными тестами, их конфи…
  6. Feb 25, 2026Чистая архитектура. Главы 3-5 Продолжаем спидран по Clean Architecture Роберта Мартина. ⭐️…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →