Числа с плавающей запятой являются приблизительными, они не могут точно хранить десятичные числа. Поскольку они пытаются представить очень большой диапазон чисел всего в 64 бита, они должны в некоторой степени приближаться.
Очень важно знать об этом, потому что это приводит к некоторым странным побочным эффектам. Например, вы можете очень разумно подумать, что сумма десяти лотов 0,1
будет 1,0
. Хотя это кажется логичным, это также неверно, когда дело касается чисел с плавающей запятой:
>>> f = 0.0
>>> for _ in range (10):
... f += 0.1
...
>>> print f == 1.0
False
>>> f
0.99999999999999989
>>> str(f)
1.0
Вы можете подумать, что n / m * m == n
. И снова мир с плавающей запятой не согласен:
>>> (1.0 / 103.0) * 103.0
0.99999999999999989
Или, возможно, так же странно, можно было бы подумать, что для всех n
, n + 1! = N
. В мире чисел с плавающей запятой числа просто не работают следующим образом:
>>> 10.0**200
9.9999999999999997e+199
>>> 10.0**200 == 10.0**200 + 1
True
# How much do we have to add to 10.0**200 before its
# floating point representation changes?
>>> 10.0**200 == 10.0**200 + 10.0**183
True
>>> 10.0**200 == 10.0**200 + 10.0**184
False
См. Что каждый компьютерный ученый должен знать о числах с плавающей запятой , где содержится превосходное резюме проблем.
Если вам нужно точное десятичное представление, ознакомьтесь с модулем decimal , который входит в стандартную библиотеку Python начиная с версии 2.4. Он позволяет указать количество значащих цифр. Обратной стороной является то, что он намного медленнее, чем с плавающей запятой, потому что операции с плавающей запятой реализованы аппаратно, тогда как десятичные операции выполняются чисто программно. У него также есть свои проблемы с неточностью, но если вам нужно точное представление десятичных чисел (например, для финансового приложения), это идеальный вариант.
Например:
>>> 3.14
3.1400000000000001
>>> import decimal
>>> decimal.Decimal('3.14')
>>> print decimal.Decimal('3.14')
3.14
# change the precision:
>>> decimal.getcontext().prec = 6
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal('0.142857')
>>> decimal.getcontext().prec = 28
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal('0.1428571428571428571428571429')
Как упоминалось ранее, все дело в приближении с плавающей запятой.
Если вам нужна точность, вы можете использовать десятичную дробь (которая является точным представлением): http://docs.python.org/library/decimal.html
a = [1.5, 1.49999]
a
[1.5, 1.4999899999999999]
from decimal import Decimal
b = [1.5, Decimal('1.4999')]
b
[1.5, Decimal('1.4999')]
Стоит отметить, что в Python 3.1 есть новая процедура вывода с плавающей точкой, которая округляет это ожидаемым образом (она также была перенесена в Python 2.7):
Python 3.1 (r31:73572, Aug 15 2009, 17:12:41)
[GCC 4.0.1 (Apple Computer, Inc. build 5367)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a = [3.14]
>>> print(a)
[3.14]
Из документа Что нового в Python 3.1:
Python теперь использует алгоритм Дэвида Гея для нахождения кратчайшего представления с плавающей точкой, которое не меняет своего значения. Это должно помочь уменьшить некоторую путаницу, связанную с двоичными числами с плавающей запятой.
Значение легко увидеть на примере такого числа, как 1.1, которое не имеет точного эквивалента в двоичной системе с плавающей запятой. Поскольку точного эквивалента нет, выражение типа
float('1.1')
оценивается в ближайшее представимое значение, которое равно0x1.199999999999ap+0
в шестнадцатеричной системе счисления или1.100000000000000088817841970012523233890533447265625
в десятичной. Это ближайшее значение использовалось и до сих пор используется в последующих вычислениях с плавающей запятой.