2012-06-28 2 views
3

Привет Я использую словарь в Python хранения некоторых городов и их населения, как, что:Неожиданные с плавающей точкой представления в Python

population = { 'Shanghai' : 17.8, 'Istanbul' : 13.3, 'Karachi' : 13.0, 'mumbai' : 12.5 } 

Теперь, если я использую команду print population, я получаю результат:

{'Karachi': 13.0, 'Shanghai': 17.800000000000001, 'Istanbul': 13.300000000000001, 'mumbai': 12.5} 

, тогда как если я использую команду print population['Shanghai'], я получаю начальный ввод 17.8.

Мой вопрос к вам, как 17.8 и 13.3 превратились в 17.800000000000001 и 13.300000000000001 соответственно? Как появилась вся эта информация? И почему он хранится там, так как мой первоначальный ввод означает, что мне не нужна эта дополнительная информация, по крайней мере, насколько я знаю.

+2

Словарь не то, что неожиданно себя для вас. Вы просто столкнулись с номерами [Floating Point] (http://en.wikipedia.org/wiki/Floating_point). – MattH

ответ

4

Это был изменен в Python 3.1. С what's new страницы:

Python теперь использует алгоритм Дэвида Гея для нахождения кратчайшего представления с плавающей точкой, которое не изменяет свое значение. Этот должен помочь смягчить некоторые путаницы вокруг двоичных чисел с плавающей запятой .

Значение можно легко увидеть с помощью номера 1.1, который имеет , не имеет точного эквивалента в двоичной плавающей запятой. Так как существует нет точного эквивалента, выражение, подобное float('1.1'), оценивается как ближайшим представительным значением, которое равно 0x1.199999999999ap+0 в шестнадцатеричном формате или 1.100000000000000088817841970012523233890533447265625 в десятичной форме. Это ближайшее значение было и остается используемым в последующих вычислениях с плавающей точкой .

Что нового рядом? Раньше Python использовал простой подход . Значение repr(1.1) было рассчитано как format(1.1, '.17g'), которое оценивалось до '1.1000000000000001'.Преимущество с использованием 17 цифр состояло в том, что он полагался на гарантии IEEE-754, чтобы обеспечить то, что eval(repr(1.1)) будет в оба конца точно до его первоначального значения. Недостаток заключается в том, что многие люди обнаружили, что результат путают (ошибочное внутреннее ограничение двоичной переменной с плавающей запятой как проблема с самим Python).

Новый алгоритм для repr(1.1) умнее и возвращает '1.1'. Фактически, он ищет все эквивалентные представления строк (те, которые , которые хранятся с одним и тем же базовым значением с плавающей запятой) и возвращает краткое представление .

Новый алгоритм имеет тенденцию выделять более чистые представления, если это возможно, , но не меняет базовые значения. Таким образом, все еще имеет место , что 1.1 + 2.2 != 3.3, хотя представления могут предложить иначе.

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

(Внесенный Эрик Смит и Марк Дикинсон; issue 1580)

2

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

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

Возможно, это связано с различиями в логике печати, используемой для двух используемых вами прецедентов. Я не мог повторить поведение (используя Python 2.7.2 в Win64).

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

+0

Благодарим за информацию. Я предполагаю, что числа с плавающей запятой должны быть такими. Я оставлю этот ответ открытым, чтобы увидеть, добавит ли кто-нибудь еще что-нибудь, какое-то время, а если нет, я его закрою. Еще раз спасибо. – NlightNFotis

+1

В обоих точках ничего не добавить, расслабиться. Когда вы «печатаете» dict, вы получаете внутреннее представление значений float, а когда вы печатаете значение float, вы получаете «строчную» (округлую) версию. Попробуйте «print repr (население [« shangai »])» и «print str (население [« shangai »])» ... –

1

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

Смотрите руководство Python для информации: http://docs.python.org/library/decimal.html

>>> from decimal import Decimal 
>>> print Decimal('3.14') 
3.14 
+0

кроме заботы - 'Десятичные' все еще числа с плавающей запятой, только с базой 10 вместо основания 2. – katrielalex

Смежные вопросы