"Правильное" округление в Python, до 3 знаков после запятой



Возможно, я упускаю что-то существенное, но я не могу найти способ "правильно" округлить плавающие/десятичные числа в Python (2.7), По крайней мере, до трех знаков после запятой. Под "правильно" я подразумеваю, что 1.2225 должен округлиться до 1.223, а 1.2224-до 1.222.



Я знаю, что round не будет работать для поплавков в Python, по дизайну, но я не могу заставить Decimal вести себя так, как ожидалось, ни функцию ceil. Поиск встроенных функций, а не пользовательских обходных путей, предпочтительно, но открытых для обоих.



>>> x = 1.2225                                   # expected: 1.223
>>> round(x, 3)
1.222 # incorrect

>>> from math import ceil

>>> ceil(x * 1000.0) / 1000.0
1.223 # correct
>>> y = 1.2224 # expected: 1.222
>>> ceil(y * 1000.0) / 1000.0
1.223 # incorrect

>>> from decimal import Decimal, ROUND_UP, ROUND_HALF_UP

>>> x = Decimal(1.2225)
>>> x.quantize(Decimal('0.001'), ROUND_UP)
Decimal('1.223') # correct
>>> y = Decimal(1.2224)
>>> y.quantize(Decimal('0.001'), ROUND_UP)
Decimal('1.223') # incorrect

>>> y.quantize(Decimal('0.001'), ROUND_HALF_UP)
Decimal('1.222') # correct
>>> x.quantize(Decimal('0.001'), ROUND_HALF_UP)
Decimal('1.222') # incorrect


Есть ли способ получить желаемый результат?
1487   3  

3 ответов:

Проблема в том, что Decimal(1.2225) не то, что вы ожидаете:

>>> Decimal(1.2225)
Decimal('1.2224999999999999200639422269887290894985198974609375')

Вы используете float для создания десятичной дроби, но этот float уже слишком неточен для вашего варианта использования. Как вы можете видеть, на самом деле это 1.222499, поэтому он меньше, чем 1.2225, и поэтому правильно округляет вниз.

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

>>> x = Decimal('1.2225')
>>> x.quantize(Decimal('0.001'), ROUND_HALF_UP)
Decimal('1.223')
>>> y = Decimal('1.2224')
>>> y.quantize(Decimal('0.001'), ROUND_HALF_UP)
Decimal('1.222')

Это то, что вы ищете?

float('{:,.3f}'.format(2.2225))

Вот три решения в этой ссылке, я надеюсь, что это поможет вам именно то, что вы хотите сделать. https://gist.github.com/jackiekazil/6201722

from decimal import Decimal

# First we take a float and convert it to a decimal
x = Decimal(16.0/7)

# Then we round it to 2 places
output = round(x,2)
# Output to screen
print output

Comments

    Ничего не найдено.