round () в Python, кажется, не округляется должным образом - PullRequest
108 голосов
/ 11 сентября 2008

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

n = 5.59
round(n, 1) # 5.6

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

5.5999999999999996

Для целей пользовательского интерфейса мне нужно отобразить 5.6. Я покопался в интернете и нашел документацию , что это зависит от моей реализации Python. К сожалению, это происходит как на моей машине с Windows, так и на каждом Linux-сервере, который я пробовал. Смотрите здесь также .

Если не считать создание моей круглой библиотеки, есть ли способ обойти это?

Ответы [ 17 ]

98 голосов
/ 11 сентября 2008

Форматирование работает правильно даже без округления:

"%.1f" % n
98 голосов
/ 11 сентября 2008

Я не могу помочь с тем, как он хранится, но по крайней мере форматирование работает правильно:

'%.1f' % round(n, 1) # Gives you '5.6'
26 голосов
/ 14 марта 2013

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

Decimal(str(16.2)).quantize(Decimal('.01'), rounding=ROUND_UP)

Это вернет десятичное число, равное 16.20.

20 голосов
/ 12 сентября 2008

round(5.59, 1) работает нормально. Проблема в том, что 5.6 нельзя представить точно в двоичной форме с плавающей запятой.

>>> 5.6
5.5999999999999996
>>> 

Как говорит Винко, вы можете использовать форматирование строк для округления для отображения.

В Python есть модуль для десятичной арифметики , если вам это нужно.

12 голосов
/ 11 сентября 2008

Вы получаете «5,6», если вы делаете str(round(n, 1)) вместо просто round(n, 1).

7 голосов
/ 11 сентября 2008

Вы можете переключить тип данных на целое число:

>>> n = 5.59
>>> int(n * 10) / 10.0
5.5
>>> int(n * 10 + 0.5)
56

А затем отобразить число, вставив десятичный разделитель локали.

Однако, Ответ Джимми лучше.

5 голосов
/ 12 июля 2010

Взгляните на десятичный модуль

Десятичный «основан на плавающей точке модель, которая была разработана с людьми в виду, и обязательно имеет первостепенный руководящий принцип - компьютеры должны обеспечивать арифметику который работает так же, как арифметика, что люди учатся в школа. »- отрывок из десятичной арифметическая спецификация.

и

Десятичные числа могут быть представлены именно так. В отличие от таких цифр, как 1,1 а на 2.2 нет точного представления в двоичном плавающем точка. Конечные пользователи обычно не ожидайте, что 1.1 + 2.2 будет отображаться как 3.3000000000000003, как это происходит с двоичной плавающей запятой.

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

5 голосов
/ 11 сентября 2008

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

4 голосов
/ 25 июня 2013

Это действительно большая проблема. Попробуйте этот код:

print "%.2f" % (round((2*4.4+3*5.6+3*4.4)/8,2),)

Показывает 4,85. Тогда вы делаете:

print "Media = %.1f" % (round((2*4.4+3*5.6+3*4.4)/8,1),)

и показывает 4,8. У вас расчеты от руки точный ответ 4,85, но если вы попробуете:

print "Media = %.20f" % (round((2*4.4+3*5.6+3*4.4)/8,20),)

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

3 голосов
/ 11 сентября 2008

printf присоска.

print '%.1f' % 5.59  # returns 5.6
...