Какие версии Python по умолчанию используют рациональную арифметику?

Если я введу следующее в оболочку Python 2.7.1 или в оболочку 3.3.2:

a = 0.1
b = 0.1
(a + b) == 0.2

он возвращает значение true. Из stackoverflow и видео из Массачусетского технологического института у меня сложилось впечатление, что это вернет false, так как есть небольшие ошибки при попытке точно представить 0.1 в компе. (В конце концов, разве это не двоичный код?) Поэтому я думаю, что Python должен либо а) выполнять арифметику с плавающей запятой, либо б) округлять перед выполнением теста на равенство.

Что это такое и какие версии Python имеют такое поведение?


person Chris Middleton    schedule 28.12.2013    source источник
comment
Попробуйте 0.1 + 0.2 == 0.3. Ошибки не должны возникать всегда.   -  person BartoszKP    schedule 29.12.2013
comment
@BartoszKP: LOL, я выбрал те же числа :)   -  person Karoly Horvath    schedule 29.12.2013
comment
@KarolyHorvath ;D Я вспомнил их, потому что недавно был вопрос именно об этом :)   -  person BartoszKP    schedule 29.12.2013


Ответы (2)


Никто из них. Это "удача". Представление с плавающей запятой + арифметика дает одно и то же значение для выбранных вами чисел.

>>> (0.1 + 0.1) == 0.2
True
>>> (0.1 + 0.2) == 0.3
False

Вы можете использовать модуль decimal, чтобы продемонстрировать это:

>>> import decimal
>>> decimal.getcontext().prec = 60
>>> decimal.Decimal(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
>>> decimal.Decimal(0.2)
Decimal('0.200000000000000011102230246251565404236316680908203125')
>>> decimal.Decimal(0.1) + decimal.Decimal(0.1)
Decimal('0.2000000000000000111022302462515654042363166809082031250')
person Karoly Horvath    schedule 28.12.2013
comment
Пока не могу принять ответ - иначе я бы. Еще один вопрос: как я могу увидеть фактическое представление 0,1 или 0,2? Я знаю, что использование операторов печати округляет ответ, но даже когда я просто набираю 0.1 в интерпретаторе, он просто выдает 0.1. ** РЕДАКТИРОВАТЬ: я вижу, вы уже собирались ответить на этот самый вопрос. Спасибо! - person Chris Middleton; 29.12.2013
comment
@AmadeusDrZaius, текущие версии Python отображают самую короткую десятичную строку, которая при обратном считывании будет точно воспроизводить число с плавающей запятой. Так много десятичных строк, которые вы вводите, будут отображаться вам дословно. - person Tim Peters; 29.12.2013
comment
@TimPeters Попался. Спасибо, Тим! - person Chris Middleton; 29.12.2013
comment
Часть удачи заключается в том, что x + x всегда является точной операцией в двоичном коде (если только не переполнение). - person dan04; 09.01.2014

Немного более глубокое объяснение: десятичное число 0,1 не может быть представлено точно как конечное двоичное число с плавающей запятой, поэтому оба экземпляра 0.1 вносят небольшие ошибки (менее 1 части в 2 ** 53, потому что в Python есть 53 бита точности). с плавающей запятой почти на всех машинах, а Python выполняет максимально возможное округление). Но плавающее сложение также подвержено собственной ошибке округления. Иногда ошибки обнуляются.

Так что «удача» — достаточно точное определение. Если вы хотите вместо этого использовать неограниченные рациональные числа, см. документацию для стандартного модуля fractions.

person Tim Peters    schedule 28.12.2013