Существует ли способ получить перекрытие Десятичного числа высокой точности в Python?
>>> import decimal;
>>> decimal.Decimal(800000000000000000001)/100000000000000000000
Decimal('8.00000000000000000001')
>>> math.ceil(decimal.Decimal(800000000000000000001)/100000000000000000000)
8.0
математика округляет значение и возвращает не точное значение
x = decimal.Decimal('8.00000000000000000000001')
with decimal.localcontext() as ctx:
ctx.prec=100000000000000000
ctx.rounding=decimal.ROUND_CEILING
y = x.to_integral_exact()
Самый прямой способ взять потолок десятичного экземпляра x
- это использовать x.to_integral_exact(rounding=ROUND_CEILING)
. Здесь нет необходимости возиться с контекстом. Обратите внимание, что это устанавливает флаги Inexact
и Rounded
, где это необходимо; если вы не хотите, чтобы флаги были затронуты, используйте x.to_integral_value(rounding=ROUND_CEILING)
вместо этого. Пример:
>>> from decimal import Decimal, ROUND_CEILING
>>> x = Decimal('-123.456')
>>> x.to_integral_exact(rounding=ROUND_CEILING)
Decimal('-123')
В отличие от большинства методов Decimal, методы to_integral_exact
и to_integral_value
не зависят от точности текущего контекста, поэтому вам не нужно беспокоиться об изменении точности:
>>> from decimal import getcontext
>>> getcontext().prec = 2
>>> x.to_integral_exact(rounding=ROUND_CEILING)
Decimal('-123')
Кстати, в Python 3. x, math.ceil
работает именно так, как вы хотите, за исключением того, что он возвращает int
, а не Decimal
. Это работает, потому что math.ceil
перегружается для пользовательских типов в Python 3. В Python 2, math.ceil
просто преобразует Decimal
в float
, потенциально теряя информацию в процессе, так что в итоге вы можете получить неправильные результаты.
>>> decimal.Context(rounding=decimal.ROUND_CEILING).quantize(
... decimal.Decimal(800000000000000000001)/100000000000000000000, 0)
Decimal('9')
def decimal_ceil(x):
int_x = int(x)
if x - int_x == 0:
return int_x
return int_x + 1
Это можно сделать, используя параметр режима точности и округления в конструкторе контекста.
ctx = decimal.Context(prec=1, rounding=decimal.ROUND_CEILING)
ctx.divide(decimal.Decimal(800000000000000000001), decimal.Decimal(100000000000000000000))
РЕДАКТИРОВАТЬ: Вам следует подумать об изменении принятого ответа. Хотя prec
может быть увеличен по мере необходимости, to_integral_exact
является более простым решением.