You are here: Home » Блог » Почему в программах Java вместо круглых цифр появляются девятки (9999999999999)?

Почему в программах Java вместо круглых цифр появляются девятки (9999999999999)?

В комментарии к учебному заданию на подсчёт денежных единиц был задан очень интересный вопрос:

Почему 10.03 * 100 = 1002.9999999999999?

Это очень важный вопрос, поскольку если не учитывать погрешности округления, можно столкнуться с трудными для выявления логическими ошибками в работе программы.

Причём погрешности могут возникать сразу в двух местах: при вычислении значения дроби и при конвертации в двоичную систему и обратно.

Давайте посмотрим такой пример:

1/3 + 1/3 + 1/3

Сколько это? Казалось бы, результат будет равен единице.

А если считать в программе?

Дробь 1/3 храниться в виде числа 0.333333333333333 (с конечным количеством цифр после точки).

Итак, если компьютер начнёт складывать 1/3 + 1/3 + 1/3, то он получит:

0.333333333333333 + 0.333333333333333 + 0.333333333333333 будет равно 0.99999999999999, а не единице.

Т.е. из-за того, что компьютер работает с числами, точность которых ограничена, а не с дробями, то теряется точность, возникают ошибки округления.

Если заглянуть ещё глубже, то компьютер понимает числа в двоичной системе счисления, т.е. в виде нулей и единиц. И наша дробь в «мозгах» компьютера переведена в двоичную систему счисления.

Например, число 0.3 (три десятых). У него теряется точность при переводе в двоичную систему счисления и обратно, поскольку для представления 0.3 в двоичной системе требуется много цифр после точки, а количество цифр ограничено.

0.3 в двоичной системе счисления это 0.01001100110011001100110011001100110011001100110011001100110011… (там ещё цифры, которые компьютер отбрасывает).

Теперь если вы конвертируете 0.01001100110011001100110011001100110011001100110011001100110011 в десятичную систему счисления, то вы получите 0.29999999999999999995663191310057982263970188796520233154296875

Т.е. для компьютера даже 1/10 + 2/10 ≠ 3/10

Для вычисления использовался онлайн конвертер:

Appendix D. What Every Computer Scientist Should Know About Floating-Point Arithmetic

2 комментария

  1. Почему в c++ тот же код выдаёт 1003?

    • Разные языки, разные наборы правил. Понятно, что в C++ происходит округление. Возможно, дело в применяемом в Java стандарте IEEE 754.

      В других языках программирования я тоже получаю тот результат, который интуитивно ожидаю. Почему в Java по-другому – мне тоже не совсем понятно. Кстати, такой результат мне кажется не совсем правильным. Здесь я описал то, как это явление объясняют преподаватели.

      И ещё по поводу C++, попробуйте поэксперементировать, когда тройка в пятой позиции после запятой – она потеряется. (Если не потеряется, то попробуйте её передвинуть в шестую и седьмую).

      Также если вас интересует тема точности, то интересный эффект даст setprecision(16) – возможно, в какой-то момент вы увидите девятки.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

wp-puzzle.com logo