Python Shell - дополнительные функции при вычитании числа с плавающей запятой

Возможное дублирование:
Ограничения с плавающей запятой

Здесь используется Python 2.7.

Может кто-нибудь объяснить, почему это происходит в оболочке?

>>> 5.2-5.0
0.20000000000000018

Поиск дал информацию о разных масштабах чисел, не дающих правильных результатов (очень маленькое число и очень большое число), но это казалось довольно общим, и, учитывая, что числа, которые я использую, имеют одинаковый масштаб, я не думаю, что вот почему это происходит.

РЕДАКТИРОВАТЬ: Я полагаю, я не определил, что «это происходит», я имел в виду, что он возвращает 0,2 ... 018, а не просто приводит к 0,2. Я получил эти раунды печати и удалил часть печати во фрагменте кода, так как это вводило в заблуждение.


person adamjseitz    schedule 25.09.2012    source источник
comment
На самом деле этот вопрос состоит из трех частей: почему 5.2 - 5.0 != 0.2, почему оценка выражения не делает то же самое, что и его печать, и почему / чем отличаются repr и str? Мой ответ сосредоточен на части 1, Ашвини Чаудхари - идеальный ответ на часть 2, а Мартейн Питерс прекрасно справляется с частью 3.   -  person abarnert    schedule 26.09.2012
comment
См. docs.python.org/tutorial/floatingpoint.html. Это гораздо более мягкое введение в проблемы, чем статья Голдберга.   -  person Mark Dickinson    schedule 26.09.2012


Ответы (4)


Вы должны понимать, что 5.2-5.0 действительно составляет 0.20000000000000018, а не 0.2. Стандартное объяснение этого можно найти в Что должен знать каждый компьютерный ученый об арифметике с плавающей запятой < / а>.

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

В Python есть несколько уловок, которые позволяют не знать то, что должен знать каждый компьютерный ученый, и при этом избежать наказания за это. Главный трюк в том, что str(f), то есть удобочитаемое представление числа с плавающей запятой, усекается до 12 значащих цифр, поэтому str(5.2-5.0) равно "0.2", а не "0.20000000000000018". Но иногда вам нужна вся возможная точность, поэтому repr(f), то есть машиночитаемое представление, не усекается, поэтому repr(5.2-5.0) равно "0.20000000000000018".

Теперь осталось понять, что делает оболочка интерпретатора. Как объясняет Ашвини Чаудхари, простая оценка чего-либо в оболочке выводит его repr, а оператор print выводит его str.

person abarnert    schedule 25.09.2012

оболочка использует repr():

In [1]: print repr(5.2-5.0)
0.20000000000000018

In [2]: print str(5.2-5.0)
0.2

In [3]: print 5.2-5.0
0.2
person Ashwini Chaudhary    schedule 25.09.2012
comment
Прошу прощения, я не очень четко сформулировал свой вопрос. Я хочу знать, почему 5.2-5.0 просто не дает 0.2? - person adamjseitz; 26.09.2012

Реализация по умолчанию float.__str__ ограничивает вывод только 12 цифрами.

Таким образом, отбрасываются наименее значащие цифры, и остается значение 0,2.

Чтобы напечатать больше цифр (если доступно), используйте форматирование строки:

print '%f' % result  # prints 0.200000

По умолчанию это 6 цифр, но вы можете указать большую точность:

print '%.16f' % result  # prints 0.2000000000000002

В качестве альтернативы python также предлагает более новый метод форматирования строк:

print '{0:.16f}'.format(result)  # prints 0.2000000000000002

Почему python выдает «неточный» результат, в первую очередь, связано с неточной природой арифметики с плавающей запятой. Если вам нужна более предсказуемая точность, используйте вместо него decimal модуль:

>>> from decimal import *
>>> getcontext().prec = 1
>>> Decimal(5.2) - Decimal(5.0)
Decimal('0.2')
person Martijn Pieters    schedule 25.09.2012

В Python есть два разных способа преобразования объекта в строку: методы __str__ и __repr__. __str__ предназначен для обычного строкового вывода и используется print; __repr__ предназначен для более точного представления и представляет собой то, что отображается, когда вы не используете print или когда вы распечатываете содержимое списка или словаря. __str__ округляет значения с плавающей запятой.

Что касается того, почему фактический результат вычитания равен 0,20000000000000018, а не 0,2, то это связано с внутренним представлением числа с плавающей запятой. Точно представить 5,2 невозможно, потому что это бесконечно повторяющееся двоичное число. Ближайшее, что вы можете найти, - это примерно 5.20000000000000018.

person Mark Ransom    schedule 25.09.2012