Найти тему
Интернет сегодня

Почему компьютеры плохо считают

Оглавление
Почему 0.21 - 0.1 != 0.11?
Почему 0.21 - 0.1 != 0.11?

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

Распространённая ошибка
Распространённая ошибка

Или же наоборот, числа в вычислениях настолько большие, что компьютер просто не в состоянии их обработать.

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

Слишком большие числа

Ошибка округления
Ошибка округления

На картинке сверху, где мы берём корень из числа, которое однозначно не является квадратом результата, явно видно округление. Поскольку количество девяток после запятой в результате больше, чем вмещает в себя стек типа float, то все остальные девятки просто округлились.

Поэтому производить какие-либо операции с большими числами нужно с особой осторожностью. Что ж, теперь перейдём к более сложным вычислениям, в мир дробей и систем счисления.

Числа с плавающей точкой

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

Ошибки вычислений
Ошибки вычислений

Проблема тут кроется не в величине чисел, а в совсем другом. Всем известно, что процессор умеет вычислять только в двоичной системе счисления, десятичную он на самом деле не понимает, а только имитирует это понимание. Давайте попробуем перевести в двоичную систему число 0.21.

Получится что-то вроде 0.001101011100001010001111010111000010..... Число, по всей видимости, бесконечное, а количество информации в одной переменной ограничено, поэтому оно обрезается, пусть будет 0.0011010111000010. Теперь то же самое проделаем и с числом 0.1: 0.0001100110011001. Вычислим разность результатов: 0.0001110000101001. И переводим в 10-тичную с.с.: 0.1100006103515625. Получилась ужасная погрешность, хотя и не в ту сторону, как в python, возможно там 2-ичные числа имеют больше знаков после запятой. В любом случае, здесь погрешность довольно велика, а значит она останется и в результате округления, так и получается это 0.10999999999999999.

А, например, при вычислении выражения 0.201 - 0.1 погрешность маленькая, округление просто уничтожает её, поэтому результат верный.

Что же делать?

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

Не очень относится к теме, но решил разбавить текст :)
Не очень относится к теме, но решил разбавить текст :)

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

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

А на сегодня всё, пока!

Наука
7 млн интересуются