6

Объясните, из-за чего происходит вот такая штука:

>>> 1 - 0.7
0.30000000000000004

и как с этим бороться?

Kromster
  • 13,809
Montreal
  • 888

3 Answers3

16

Дело в том, что в памяти числа хранятся в двоичном виде, а 0.3 в двоичном виде выглядит как бесконечная периодическая дробь (0.0100110011001...). В память бесконечное число цифр, понятное дело, не запишешь, поэтому реально там хранится число чуть меньше, чем 0.3. При вычитании этого числа из 1 и выводе на экран эта небольшая разница и выплывает наружу. Что с этим делать - смириться с несовершенством мира и при выводе округлять до приемлемого числа знаков.

Подробнее о представлении чисел с плавающей запятой тонкостях операций с ними: статья на Хабре

insolor
  • 49,104
11

Такова природа чисел с плавающей запятой: они описываются через экспоненту, и их "шаг" может выглядеть довольно странно, однако обычно он достаточно мал, чтобы избежать серьезных ошибок. В документации, насколько понял, рекомендуют использовать round().

etki
  • 36,151
  • Спасибо за подсказку! – Montreal Jan 25 '14 at 19:58
  • 1
    @Fike проблема не в экспоненте, как уже описано в ответе @insolor – alexlz Jan 26 '14 at 02:06
  • @alexlz, мы написали, в общем-то, одно и то же, экспонента только там не обычное е. – etki Jan 26 '14 at 08:32
  • Еще можно использовать числа с фиксированной точностью (Decimal) – Nitive Jan 26 '14 at 08:50
  • @samoilow Ну а можно бы и числа с плавающей запятой, но десятичные :). (Правда не скажу, есть ли такие устройства). Двоичные числа с фиксированной запятой порождают ту же проблему. @Fike лениво написать лишнее слово? "обычное e" -- это 2.718281828459045 (я понял, что Вы хотели написать "обычное 10", но написали немного другое). – alexlz Jan 26 '14 at 09:14
  • 2
    @alexlz, я ответил немного позже, поэтому мой ответ можно считать уточняющим :)

    @Fike, если быть совсем точным, числа с плавающей запятой хранятся в виде мантиссы (множителя) и порядка (показателя степени), основание подразумевается равным 2. И под мантиссу и под порядок отводится ограниченное количество двоичных разрядов, отсюда и всяческие погрешности.

    – insolor Jan 26 '14 at 09:37
2

Ещё можно попытаться привести числа с плавающей запятой к целым числам. Например, следующее неравенство:

1 - 0.7 > 0.3

(на которое python мне ответил True) можно заменить на эквивалентное домножив обе части на 10:

10 - 7 > 3

Тут я уже, как и ожидалось, получил False.

pank
  • 2,548
  • разве это ответ на заданный вопрос? – aleksandr barakin Feb 24 '16 at 21:21
  • Ну, человек спросил "как с этим бороться?". Я предложил вариант как можно в определённой ситуации бороться с ошибками в округлении. – pank Feb 24 '16 at 22:01