В комментарии к учебному заданию на подсчёт денежных единиц был задан очень интересный вопрос:
Почему 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
Для вычисления использовался
Почему в c++ тот же код выдаёт 1003?
Разные языки, разные наборы правил. Понятно, что в C++ происходит округление. Возможно, дело в применяемом в Java стандарте IEEE 754.
В других языках программирования я тоже получаю тот результат, который интуитивно ожидаю. Почему в Java по-другому – мне тоже не совсем понятно. Кстати, такой результат мне кажется не совсем правильным. Здесь я описал то, как это явление объясняют преподаватели.
И ещё по поводу C++, попробуйте поэксперементировать, когда тройка в пятой позиции после запятой – она потеряется. (Если не потеряется, то попробуйте её передвинуть в шестую и седьмую).
Также если вас интересует тема точности, то интересный эффект даст setprecision(16) – возможно, в какой-то момент вы увидите девятки.