Как компьютеры могут совершать такие глупые ошибки?
Современные цифровые компьютеры прошли долгий путь. Компьютеры стали основой, на которой в последние годы были сделаны научно-технические достижения. Так что немного забавно думать, что компьютеры дают странные результаты для некоторых операций с плавающей запятой, которые кажутся интуитивно понятными даже малышам. В этой статье мы попытаемся понять, почему так?
0.1 + 0.2 != 0.3
Я показываю это в интерпретаторе Python, но вы можете увидеть проблему на каждом языке программирования.
>>> 0.1 + 0.2 == 0.3 False >>> 1.0 +2.0 3.0
Когда мы пытаемся посмотреть на результат суммы в питоне, мы не видим ничего странного.
>>> 1.0 +2.0 3.0
Для новичков в этом вопросе это может выглядеть как ошибка. Но это не так. Представление с плавающей запятой и арифметика не точны. Это связано с фактической реализацией того, как в системе обрабатывается число с плавающей запятой. Под капотом python показывает приближение при отображении данных. Несмотря на то, что Python показывает нам значение 3, это не так. Чтобы увидеть фактическое представление, которое мы можем сделать.
>>> from decimal import Decimal >>> Decimal(0.1) + Decimal(0.2) Decimal(‘0.3000000000000000166533453694’)
Числа с фиксированной точкой
Как вы слышали сто или двести тысяч раз. Компьютер понимает все с точки зрения 1 и 0. В том числе и сами дроби. Таким образом, любое основание 2 может быть представлено правильно и даст точные результаты. Возьмите пример ниже.
>>> Decimal(1/2)+Decimal(1/4) Decimal(‘0.75’)
Числа могут быть точно представлены в степени 2. Таким образом, после цифровой точки имеется фиксированное количество цифр. Такие числа называются числами с фиксированной точкой. Фиксированные номера очень быстрые, но не гибкие. Он может представлять только ограниченный диапазон значений.
Числа с плавающей запятой
Возьмем, к примеру, 0.1
. Для нас 0.1
кажется интуитивно понятным, потому что мы следуем основанию 10. Что касается компьютеров, мы видим странное поведение, потому что компьютеры пытаются представить его в терминах основания 2. Что невозможно.
>>> Decimal.from_float(0.1) Decimal('0.1000000000000000055511151231257827021181583404541015625')
Для чисел, в которых не используются целые и дробные числа, решение — с плавающей запятой. Это используется для представления нецелых дробных чисел. С плавающей запятой допускается различное количество цифр после запятой.
IEEE-754
Давайте представим число 1/3
. Число не является идеальной дробью. И теоретически его точность равна бесконечности. Как мы представляем это в компьютерах? В конце концов, мы не можем сохранить все, у компьютеров ограниченная память. Так что где-то по пути нам нужно его обрезать.
Для обычного программиста, выполняющего базовые сценарии, число 101 или 101.00000001 не имеет значения. Для ученого это может быть огромным красным флагом. Так кто определяет точность?
Большинство машин используют арифметику с плавающей запятой IEEE-754. Компьютеры пытаются представить числа как можно ближе к форме (-1)**(sign) * F / (2**e)
. Здесь F
— это мантисса, а e
— экспонента. И оба целые. Sign
является старшим битом и может быть равен 0 или 1.
В python числа с плавающей точкой сопоставляются с двойной точностью IEEE-754. Это означает, что F или мантисса является целым числом с 53 битами.
Давайте посмотрим пример. Давайте посмотрим, как представлено 0.1
:
>>> from fractions import Fraction >>> Fraction.from_float(0.1) Fraction(3602879701896397, 36028797018963968) >>> log(36028797018963968,2) 55.00000000000001
Здесь,
- Знак 1
- Показатель 55
- Мантисса 3602879701896397
>>> calc = lambda sign, F, e: (-1)**(sign) * F / (2**e) >>> calc(0, 3602879701896397, 55) 0.1
Резюме
Эта статья была грубым упрощением ошибки с плавающей запятой. Для более подробного объяснения вы можете обратиться к:
Присоединяйтесь к FAUN: Сайт💻|Подкаст🎙️|Twitter🐦|Facebook👥 |Instagram📷|Группа Facebook🗣️|Группа Linkedin💬| Slack 📱|Cloud Native Новости📰|Дополнительно.
Если этот пост был полезен, пожалуйста, несколько раз нажмите кнопку аплодисментов 👏 ниже, чтобы выразить свою поддержку автору 👇