Spec-Zone.ru › Python 3.14

decimal — Десятичная арифметика с фиксированной и плавающей точкой

Исходный код: Lib/decimal.py

Модуль decimal обеспечивает поддержку быстрой и правильно округляемой десятичной арифметики с плавающей точкой. Он имеет несколько преимуществ перед типом данных float:

  • Десятичная арифметика «основана на модели чисел с плавающей точкой, разработанной с учётом потребностей людей, и, разумеется, руководствуется главным принципом: компьютеры должны обеспечивать арифметические вычисления, работающие так же, как арифметика, которой учат в школе». — выдержка из спецификации десятичной арифметики.
  • Десятичные числа можно представлять точно. В отличие от них, такие числа, как 1.1 и 2.2, не имеют точного представления в двоичной арифметике с плавающей точкой. Обычно конечные пользователи не ожидают, что 1.1 + 2.2 будет отображаться как 3.3000000000000003, как это происходит при использовании двоичной арифметики с плавающей точкой.
  • Точность сохраняется и при арифметических операциях. В десятичной арифметике с плавающей точкой 0.1 + 0.1 + 0.1 - 0.3 в точности равно нулю. В двоичной арифметике с плавающей точкой результат равен 5.5511151231257827e-017. Хотя он близок к нулю, это различие не позволяет надёжно проверять равенство и может накапливаться. По этой причине десятичная арифметика предпочтительна в бухгалтерских приложениях, где требуются строгие инварианты равенства.
  • Модуль decimal учитывает значащие разряды, поэтому 1.30 + 1.20 — это 2.50. Конечный ноль сохраняется, чтобы указывать на значимость разряда. Такое представление обычно используется в финансовых приложениях. При умножении «школьный» подход использует все цифры множителей. Например, 1.3 * 1.2 даёт 1.56, а 1.30 * 1.20 даёт 1.5600.
  • В отличие от аппаратной двоичной арифметики с плавающей точкой, модуль decimal позволяет пользователю изменять точность (по умолчанию — 28 разрядов), увеличивая её настолько, насколько требуется для конкретной задачи:

    >>> from decimal import *
    >>> getcontext().prec = 6
    >>> Decimal(1) / Decimal(7)
    Decimal('0.142857')
    >>> getcontext().prec = 28
    >>> Decimal(1) / Decimal(7)
    Decimal('0.1428571428571428571428571429')
    
  • Двоичная и десятичная арифметика с плавающей точкой реализованы в соответствии с опубликованными стандартами. Встроенный тип float предоставляет лишь небольшую часть своих возможностей, тогда как модуль decimal предоставляет все части стандарта, которые должны быть реализованы. При необходимости программист может полностью управлять округлением и обработкой сигналов. Это включает возможность обеспечить точную арифметику, используя исключения для блокировки любых неточных операций.
  • Модуль decimal разработан для поддержки «как точной неокруглённой десятичной арифметики (иногда называемой арифметикой с фиксированной точкой), так и округляемой арифметики с плавающей точкой — без предпочтения одного варианта другому». — выдержка из спецификации десятичной арифметики.

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

Десятичное число неизменяемо. Оно состоит из знака, цифр коэффициента и показателя степени. Чтобы сохранить значимость, конечные нули в цифрах коэффициента не отбрасываются. Десятичные числа также включают специальные значения, такие как Infinity, -Infinity и NaN. Стандарт также различает -0 и +0.

Контекст арифметических операций — это среда, задающая точность, правила округления, ограничения показателей степени, флаги, указывающие на результаты операций, и обработчики ловушек, определяющие, считаются ли сигналы исключениями. Варианты округления включают ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_UP и ROUND_05UP.

Сигналы — это группы исключительных условий, возникающих в ходе вычислений. В зависимости от потребностей приложения сигналы можно игнорировать, считать информационными или обрабатывать как исключения. Сигналы в модуле decimal: Clamped, InvalidOperation, DivisionByZero, Inexact, Rounded, Subnormal, Overflow, Underflow и FloatOperation.

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

См. также

  • Спецификация общей десятичной арифметики IBM: Спецификация общей десятичной арифметики.

Краткое руководство

Обычно для начала работы с десятичными числами импортируют модуль, просматривают текущий контекст с помощью getcontext() и при необходимости задают новые значения точности, округления или включённых ловушек:

>>> from decimal import *
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
        capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
        InvalidOperation])

>>> getcontext().prec = 7       # Set a new precision

Экземпляры Decimal можно создавать из целых чисел, строк, чисел с плавающей точкой или кортежей. При создании из целого числа или числа с плавающей точкой выполняется точное преобразование значения этого числа. Десятичные числа включают специальные значения, такие как NaN, означающее «не число», положительную и отрицательную бесконечность Infinity, а также -0:

>>> getcontext().prec = 28
>>> Decimal(10)
Decimal('10')
>>> Decimal('3.14')
Decimal('3.14')
>>> Decimal(3.14)
Decimal('3.140000000000000124344978758017532527446746826171875')
>>> Decimal((0, (3, 1, 4), -2))
Decimal('3.14')
>>> Decimal(str(2.0 ** 0.5))
Decimal('1.4142135623730951')
>>> Decimal(2) ** Decimal('0.5')
Decimal('1.414213562373095048801688724')
>>> Decimal('NaN')
Decimal('NaN')
>>> Decimal('-Infinity')
Decimal('-Infinity')

Если для сигнала FloatOperation включена ловушка, случайное смешивание десятичных чисел и чисел с плавающей точкой при создании объектов или сравнении порядка вызывает исключение:

>>> c = getcontext()
>>> c.traps[FloatOperation] = True
>>> Decimal(3.14)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') < 3.7
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') == 3.5
True

Добавлено в версии 3.3.

Значимость нового объекта Decimal определяется только количеством введённых цифр. Точность контекста и округление учитываются только во время арифметических операций.

>>> getcontext().prec = 6
>>> Decimal('3.0')
Decimal('3.0')
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988')

Если превышены внутренние ограничения версии на C, создание десятичного числа вызывает InvalidOperation:

>>> Decimal("1e9999999999999999999")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]

Изменено в версии 3.3.

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

>>> data = list(map(Decimal, '1.34 1.87 3.45 2.35 1.00 0.03 9.25'.split()))
>>> max(data)
Decimal('9.25')
>>> min(data)
Decimal('0.03')
>>> sorted(data)
[Decimal('0.03'), Decimal('1.00'), Decimal('1.34'), Decimal('1.87'),
 Decimal('2.35'), Decimal('3.45'), Decimal('9.25')]
>>> sum(data)
Decimal('19.29')
>>> a,b,c = data[:3]
>>> str(a)
'1.34'
>>> float(a)
1.34
>>> round(a, 1)
Decimal('1.3')
>>> int(a)
1
>>> a * 5
Decimal('6.70')
>>> a * b
Decimal('2.5058')
>>> c % a
Decimal('0.77')

Десятичные числа можно форматировать (с помощью встроенной функции format() или f-строк) в формате с фиксированной точкой или в экспоненциальной нотации, используя тот же синтаксис форматирования (см. Мини-язык спецификаций формата), что и для встроенного типа float:

>>> format(Decimal('2.675'), "f")
'2.675'
>>> format(Decimal('2.675'), ".2f")
'2.68'
>>> f"{Decimal('2.675'):.2f}"
'2.68'
>>> format(Decimal('2.675'), ".2e")
'2.68e+0'
>>> with localcontext() as ctx:
...     ctx.rounding = ROUND_DOWN
...     print(format(Decimal('2.675'), ".2f"))
...
2.67

Для Decimal доступны и некоторые математические функции:

>>> getcontext().prec = 28
>>> Decimal(2).sqrt()
Decimal('1.414213562373095048801688724')
>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal('10').ln()
Decimal('2.302585092994045684017991455')
>>> Decimal('10').log10()
Decimal('1')

Метод quantize() округляет число до заданного показателя степени. Этот метод полезен в финансовых приложениях, где результаты часто округляют до фиксированного числа разрядов:

>>> Decimal('7.325').quantize(Decimal('.01'), rounding=ROUND_DOWN)
Decimal('7.32')
>>> Decimal('7.325').quantize(Decimal('1.'), rounding=ROUND_UP)
Decimal('8')

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

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

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

>>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN)
>>> setcontext(myothercontext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857142857142857142857142857')

>>> ExtendedContext
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
        capitals=1, clamp=0, flags=[], traps=[])
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857143')
>>> Decimal(42) / Decimal(0)
Decimal('Infinity')

>>> setcontext(BasicContext)
>>> Decimal(42) / Decimal(0)
Traceback (most recent call last):
  File "<pyshell#143>", line 1, in -toplevel-
    Decimal(42) / Decimal(0)
DivisionByZero: x / 0

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

>>> setcontext(ExtendedContext)
>>> getcontext().clear_flags()
>>> Decimal(355) / Decimal(113)
Decimal('3.14159292')
>>> getcontext()
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
        capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])

Запись flags показывает, что рациональное приближение числа пи было округлено (цифры, выходящие за пределы точности контекста, отброшены), а результат неточен (некоторые из отброшенных цифр были ненулевыми).

Отдельные ловушки настраиваются с помощью словаря в атрибуте контекста traps:

>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(0)
Decimal('Infinity')
>>> getcontext().traps[DivisionByZero] = 1
>>> Decimal(1) / Decimal(0)
Traceback (most recent call last):
  File "<pyshell#112>", line 1, in -toplevel-
    Decimal(1) / Decimal(0)
DivisionByZero: x / 0

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

Объекты Decimal

class decimal.Decimal(value='0', context=None)

Создает новый объект Decimal на основе value.

value может быть целым числом, строкой, кортежем, float или другим объектом Decimal. Если value не задано, возвращается Decimal('0'). Если value — строка, она должна соответствовать синтаксису десятичной числовой строки после удаления начальных и конечных пробельных символов, а также символов подчеркивания в любом месте:

sign           ::=  '+' | '-'
digit          ::=  '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
indicator      ::=  'e' | 'E'
digits         ::=  digit [digit]...
decimal-part   ::=  digits '.' [digits] | ['.'] digits
exponent-part  ::=  indicator [sign] digits
infinity       ::=  'Infinity' | 'Inf'
nan            ::=  'NaN' [digits] | 'sNaN' [digits]
numeric-value  ::=  decimal-part [exponent-part] | infinity
numeric-string ::=  [sign] numeric-value | [sign] nan

Вместо digit, указанного выше, также допускаются другие десятичные цифры Unicode. К ним относятся десятичные цифры из различных других алфавитов (например, арабско-индийские цифры и цифры деванагари), а также полноширинные цифры от '\uff10' до '\uff19'. Регистр не имеет значения, поэтому, например, inf, Inf, INFINITY и iNfINity — допустимые варианты записи положительной бесконечности.

Если value — tuple, он должен содержать три компонента: знак (0 для положительного или 1 для отрицательного числа), tuple цифр и целый показатель степени. Например, Decimal((0, (1, 4, 1, 4), -3)) возвращает Decimal('1.414').

Если value — float, двоичное число с плавающей точкой преобразуется без потерь в точный десятичный эквивалент. Для такого преобразования часто требуется точность в 53 или более цифр. Например, Decimal(float('1.1')) преобразуется в Decimal('1.100000000000000088817841970012523233890533447265625').

Точность context не влияет на количество сохраняемых цифр. Оно определяется исключительно количеством цифр в value. Например, Decimal('3.00000') сохраняет все пять нулей, даже если точность контекста равна всего трем.

Аргумент context определяет, что делать, если value — некорректная строка. Если контекст перехватывает сигнал InvalidOperation, возникает исключение; в противном случае конструктор возвращает новый Decimal со значением NaN.

После создания объекты Decimal неизменяемы.

Изменено в версии 3.2: Теперь аргументом конструктора может быть экземпляр float.

Изменено в версии 3.3: Аргументы float вызывают исключение, если установлен перехватчик FloatOperation. По умолчанию перехватчик выключен.

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

Десятичные числа с плавающей точкой обладают многими свойствами других встроенных числовых типов, таких как float и int. К ним применимы все обычные математические операции и специальные методы. Аналогично, объекты Decimal можно копировать, сериализовать с помощью pickle, выводить, использовать в качестве ключей словарей и элементов множеств, сравнивать, сортировать и преобразовывать в другой тип (например, float или int).

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

>>> (-7) % 4
1
>>> Decimal(-7) % Decimal(4)
Decimal('-3')

Оператор целочисленного деления // работает аналогичным образом: он возвращает целую часть частного (усекая результат к нулю), а не его округление вниз, чтобы сохранялось обычное тождество x == (x // y) * y + x % y:

>>> -7 // 4
-2
>>> Decimal(-7) // Decimal(4)
Decimal('-1')

Операторы % и // реализуют операции remainder и divide-integer (соответственно), описанные в спецификации.

Объекты Decimal обычно нельзя смешивать с числами с плавающей точкой или экземплярами fractions.Fraction в арифметических операциях: например, попытка сложить Decimal и float вызовет TypeError. Однако операторы сравнения Python позволяют сравнивать экземпляр Decimal x с другим числом y. Это позволяет избежать неожиданных результатов при сравнении на равенство чисел разных типов.

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

Помимо стандартных числовых свойств, десятичные числа с плавающей точкой имеют ряд специализированных методов:

adjusted()

Возвращает скорректированный показатель степени, полученный удалением крайних правых цифр коэффициента до тех пор, пока не останется только старшая цифра: Decimal('321e+5').adjusted() возвращает семь. Используется для определения положения самой значащей цифры относительно десятичной точки.

as_integer_ratio()

Возвращает пару (n, d) целых чисел, представляющих заданный экземпляр Decimal в виде дроби, несократимой и с положительным знаменателем:

>>> Decimal('-3.14').as_integer_ratio()
(-157, 50)

Преобразование выполняется точно. Для бесконечностей возникает OverflowError, а для NaN — ValueError.

Добавлено в версии 3.6.

as_tuple()

Возвращает представление числа в виде именованного кортежа: DecimalTuple(sign, digits, exponent).

canonical()

Возвращает каноническое представление аргумента. В настоящее время представление экземпляра Decimal всегда является каноническим, поэтому эта операция возвращает аргумент без изменений.

compare(other, context=None)

Сравнивает значения двух экземпляров Decimal. compare() возвращает экземпляр Decimal; если хотя бы один операнд — NaN, результатом также будет NaN:

a or b is a NaN  ==> Decimal('NaN')
a < b            ==> Decimal('-1')
a == b           ==> Decimal('0')
a > b            ==> Decimal('1')
compare_signal(other, context=None)

Эта операция идентична методу compare(), за исключением того, что все значения NaN вызывают сигнал. То есть, если ни один из операндов не является сигнализирующим NaN, любой тихий NaN-операнд рассматривается как сигнализирующий NaN.

compare_total(other, context=None)

Сравнивает два операнда по их абстрактному представлению, а не по числовому значению. Метод похож на compare(), но результат задает полный порядок для экземпляров Decimal. Два экземпляра Decimal с одинаковым числовым значением, но разными представлениями, в этом порядке считаются неравными:

>>> Decimal('12.0').compare_total(Decimal('12'))
Decimal('-1')

Тихие и сигнализирующие NaN также включены в полный порядок. Результат этой функции равен Decimal('0'), если оба операнда имеют одинаковое представление, Decimal('-1'), если первый операнд находится ниже второго в полном порядке, и Decimal('1'), если первый операнд находится выше второго. Подробное описание полного порядка см. в спецификации.

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

compare_total_mag(other, context=None)

Сравнивает два операнда по их абстрактному представлению, а не по значению, как в compare_total(), но игнорируя знак каждого операнда. x.compare_total_mag(y) эквивалентен x.copy_abs().compare_total(y.copy_abs()).

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

conjugate()

Просто возвращает self; этот метод нужен только для соответствия спецификации Decimal.

copy_abs()

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

copy_negate()

Возвращает отрицание аргумента. Эта операция не зависит от контекста и является тихой: флаги не меняются, округление не выполняется.

copy_sign(other, context=None)

Возвращает копию первого операнда со знаком, совпадающим со знаком второго операнда. Например:

>>> Decimal('2.3').copy_sign(Decimal('-1.5'))
Decimal('-2.3')

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

exp(context=None)

Возвращает значение функции (натуральной) экспоненты e**x для заданного числа. Результат правильно округляется с использованием режима округления ROUND_HALF_EVEN.

>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal(321).exp()
Decimal('2.561702493119680037517373933E+139')
classmethod from_float(f, /)

Альтернативный конструктор, принимающий только экземпляры float или int.

Обратите внимание: Decimal.from_float(0.1) — это не то же самое, что Decimal('0.1'). Поскольку 0.1 нельзя точно представить в двоичном формате с плавающей точкой, сохраняется ближайшее представимое значение — 0x1.999999999999ap-4. Его десятичный эквивалент — 0.1000000000000000055511151231257827021181583404541015625.

Примечание

Начиная с Python 3.2, экземпляр Decimal можно также создать непосредственно из float.

>>> Decimal.from_float(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
>>> Decimal.from_float(float('nan'))
Decimal('NaN')
>>> Decimal.from_float(float('inf'))
Decimal('Infinity')
>>> Decimal.from_float(float('-inf'))
Decimal('-Infinity')

Добавлено в версии 3.1.

classmethod from_number(number, /)

Альтернативный конструктор, принимающий только экземпляры float, int или Decimal, но не строки или кортежи.

>>> Decimal.from_number(314)
Decimal('314')
>>> Decimal.from_number(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
>>> Decimal.from_number(Decimal('3.14'))
Decimal('3.14')

Добавлено в версии 3.14.

fma(other, third, context=None)

Умножение с последующим сложением без промежуточного округления. Возвращает self*other+third без округления промежуточного произведения self*other.

>>> Decimal(2).fma(3, 5)
Decimal('11')
is_canonical()

Возвращает True, если аргумент канонический, и False в противном случае. В настоящее время экземпляр Decimal всегда является каноническим, поэтому эта операция всегда возвращает True.

is_finite()

Возвращает True, если аргумент является конечным числом, и False, если аргумент — бесконечность или NaN.

is_infinite()

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

is_nan()

Возвращает True, если аргумент — (тихий или сигнализирующий) NaN, и False в противном случае.

is_normal(context=None)

Возвращает True, если аргумент является нормальным конечным числом. Возвращает False, если аргумент равен нулю, является субнормальным, бесконечным или NaN.

is_qnan()

Возвращает True, если аргумент — тихий NaN, и False в противном случае.

is_signed()

Возвращает True, если аргумент имеет отрицательный знак, и False в противном случае. Обратите внимание, что нули и NaN могут иметь знак.

is_snan()

Возвращает True, если аргумент — сигнализирующий NaN, и False в противном случае.

is_subnormal(context=None)

Возвращает True, если аргумент является субнормальным, и False в противном случае.

is_zero()

Возвращает True, если аргумент равен (положительному или отрицательному) нулю, и False в противном случае.

ln(context=None)

Возвращает натуральный логарифм (по основанию e) операнда. Результат правильно округляется с использованием режима округления ROUND_HALF_EVEN.

log10(context=None)

Возвращает десятичный логарифм операнда. Результат правильно округляется с использованием режима округления ROUND_HALF_EVEN.

logb(context=None)

Для ненулевого числа возвращает скорректированный показатель степени операнда в виде экземпляра Decimal. Если операнд равен нулю, возвращается Decimal('-Infinity') и устанавливается флаг DivisionByZero. Если операнд — бесконечность, возвращается Decimal('Infinity').

logical_and(other, context=None)

logical_and() — логическая операция, принимающая два логических операнда (см. Логические операнды). Результатом является побитовое and двух операндов поразрядно.

logical_invert(context=None)

logical_invert() — логическая операция. Результатом является инверсия каждого разряда операнда.

logical_or(other, context=None)

logical_or() — логическая операция, принимающая два логических операнда (см. Логические операнды). Результатом является побитовое or двух операндов поразрядно.

logical_xor(other, context=None)

logical_xor() — логическая операция, принимающая два логических операнда (см. Логические операнды). Результатом является поразрядная операция исключающего ИЛИ для двух операндов.

max(other, context=None)

Аналогичен max(self, other), за исключением того, что перед возвратом применяется правило округления контекста, а значения NaN либо вызывают сигнал, либо игнорируются (в зависимости от контекста и от того, являются ли они сигнализирующими или тихими).

max_mag(other, context=None)

Похож на метод max(), но сравнение выполняется по абсолютным значениям операндов.

min(other, context=None)

Аналогичен min(self, other), за исключением того, что перед возвратом применяется правило округления контекста, а значения NaN либо вызывают сигнал, либо игнорируются (в зависимости от контекста и от того, являются ли они сигнализирующими или тихими).

min_mag(other, context=None)

Похож на метод min(), но сравнение выполняется по абсолютным значениям операндов.

next_minus(context=None)

Возвращает наибольшее число, представимое в заданном контексте (или в контексте текущего потока, если контекст не задан), которое меньше заданного операнда.

next_plus(context=None)

Возвращает наименьшее число, представимое в заданном контексте (или в контексте текущего потока, если контекст не задан), которое больше заданного операнда.

next_toward(other, context=None)

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

normalize(context=None)

Используется для получения канонических значений класса эквивалентности в текущем или указанном контексте.

Семантика этого метода совпадает с семантикой унарного оператора «плюс», за исключением того, что конечный результат приводится к простейшей форме: все конечные нули удаляются, а знак сохраняется. То есть, пока коэффициент ненулевой и кратен десяти, он делится на десять, а показатель степени увеличивается на 1. В противном случае (если коэффициент равен нулю) показатель степени устанавливается в 0. Во всех случаях знак не меняется.

Например, Decimal('32.100') и Decimal('0.321000e+2') нормализуются до эквивалентного значения Decimal('32.1').

Обратите внимание, что округление выполняется до приведения к простейшей форме.

В последних версиях спецификации эта операция также называется reduce.

number_class(context=None)

Возвращает строку, описывающую класс операнда. Возвращаемое значение — одна из следующих десяти строк.

  • "-Infinity" — операнд является отрицательной бесконечностью.
  • "-Normal" — операнд является отрицательным нормальным числом.
  • "-Subnormal" — операнд отрицателен и является субнормальным.
  • "-Zero" — операнд является отрицательным нулем.
  • "+Zero" — операнд является положительным нулем.
  • "+Subnormal" — операнд положителен и является субнормальным.
  • "+Normal" — операнд является положительным нормальным числом.
  • "+Infinity" — операнд является положительной бесконечностью.
  • "NaN" — операнд является тихим NaN (не числом).
  • "sNaN" — операнд является сигнализирующим NaN.
quantize(exp, rounding=None, context=None)

Возвращает значение, равное первому операнду после округления и имеющее показатель степени второго операнда.

>>> Decimal('1.41421356').quantize(Decimal('1.000'))
Decimal('1.414')

В отличие от других операций, если длина коэффициента после операции quantize превышает точность, возникает сигнал InvalidOperation. Это гарантирует, что при отсутствии ошибки показатель степени результата quantize всегда равен показателю степени правого операнда.

Кроме того, в отличие от других операций, quantize никогда не вызывает Underflow, даже если результат субнормальный и неточный.

Если показатель степени второго операнда больше показателя степени первого, может потребоваться округление. В этом случае режим округления определяется аргументом rounding, если он задан, иначе — заданным аргументом context; если ни один из аргументов не задан, используется режим округления контекста текущего потока.

Если показатель степени результата больше Emax или меньше Etiny(), возвращается ошибка.

radix()

Возвращает Decimal(10) — основание системы счисления, в которой класс Decimal выполняет все вычисления. Включен для совместимости со спецификацией.

remainder_near(other, context=None)

Возвращает остаток от деления self на other. Этот метод отличается от self % other тем, что знак остатка выбирается так, чтобы минимизировать его абсолютное значение. Точнее, возвращаемое значение равно self - n * other, где n — целое число, ближайшее к точному значению self / other; если два целых числа равноудалены, выбирается четное.

Если результат равен нулю, его знак совпадает со знаком self.

>>> Decimal(18).remainder_near(Decimal(10))
Decimal('-2')
>>> Decimal(25).remainder_near(Decimal(10))
Decimal('5')
>>> Decimal(35).remainder_near(Decimal(10))
Decimal('-5')
rotate(other, context=None)

Возвращает результат циклического сдвига цифр первого операнда на величину, заданную вторым операндом. Второй операнд должен быть целым числом в диапазоне от -precision до precision. Абсолютное значение второго операнда задает количество позиций сдвига. Если второй операнд положителен, сдвиг выполняется влево; в противном случае — вправо. При необходимости коэффициент первого операнда дополняется слева нулями до длины precision. Знак и показатель степени первого операнда не меняются.

same_quantum(other, context=None)

Проверяет, совпадают ли показатели степени у self и other или являются ли оба операнда NaN.

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

scaleb(other, context=None)

Возвращает первый операнд с показателем степени, измененным на величину второго операнда. Иными словами, возвращает первый операнд, умноженный на 10**other. Второй операнд должен быть целым числом.

shift(other, context=None)

Возвращает результат сдвига цифр первого операнда на величину, заданную вторым операндом. Второй операнд должен быть целым числом в диапазоне от -precision до precision. Абсолютное значение второго операнда задает количество позиций сдвига. Если второй операнд положителен, сдвиг выполняется влево; в противном случае — вправо. В коэффициент при сдвиге добавляются нули. Знак и показатель степени первого операнда не меняются.

sqrt(context=None)

Возвращает квадратный корень аргумента с полной точностью.

to_eng_string(context=None)

Преобразует значение в строку, используя инженерную нотацию, если требуется показатель степени.

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

Например, Decimal('123E+1') преобразуется в Decimal('1.23E+3').

to_integral(rounding=None, context=None)

Идентичен методу to_integral_value(). Имя to_integral сохранено для совместимости со старыми версиями.

to_integral_exact(rounding=None, context=None)

Округляет до ближайшего целого числа, сигнализируя Inexact или Rounded, если происходит округление. Режим округления определяется параметром rounding, если он указан, иначе используется заданный context. Если не указан ни один из параметров, используется режим округления текущего контекста.

to_integral_value(rounding=None, context=None)

Округляет до ближайшего целого числа, не сигнализируя Inexact или Rounded. Если задан параметр rounding, он применяется; в противном случае используется метод округления из переданного context или текущего контекста.

Десятичные числа можно округлять с помощью функции round():

round(number)
round(number, ndigits)

Если ndigits не задан или равен None, возвращает ближайшее int к number, округляя значения посередине до ближайшего чётного, и игнорируя режим округления контекста Decimal. Вызывает OverflowError, если number — бесконечность, или ValueError, если это (тихий или сигнальный) NaN.

Если ndigits — это int, учитывается режим округления контекста, а возвращается Decimal, представляющее number, округлённое до ближайшего кратного Decimal('1E-ndigits'); в этом случае round(number, ndigits) эквивалентно self.quantize(Decimal('1E-ndigits')). Возвращает Decimal('NaN'), если number — тихий NaN. Вызывает InvalidOperation, если number — бесконечность, сигнальный NaN или если длина коэффициента после операции quantize превышает точность текущего контекста. Иными словами, в обычных случаях:

  • если ndigits положительно, возвращается number, округлённое до ndigits знаков после запятой;
  • если ndigits равно нулю, возвращается number, округлённое до ближайшего целого числа;
  • если ndigits отрицательно, возвращается number, округлённое до ближайшего кратного 10**abs(ndigits).

Например:

>>> from decimal import Decimal, getcontext, ROUND_DOWN
>>> getcontext().rounding = ROUND_DOWN
>>> round(Decimal('3.75'))     # context rounding ignored
4
>>> round(Decimal('3.5'))      # round-ties-to-even
4
>>> round(Decimal('3.75'), 0)  # uses the context rounding
Decimal('3')
>>> round(Decimal('3.75'), 1)
Decimal('3.7')
>>> round(Decimal('3.75'), -1)
Decimal('0E+1')

Логические операнды

Методы logical_and(), logical_invert(), logical_or() и logical_xor() ожидают, что их аргументы будут логическими операндами. Логический операнд — это экземпляр Decimal, показатель степени и знак которого равны нулю, а все цифры — 0 или 1.

Объекты контекста

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

У каждого потока есть собственный текущий контекст, к которому можно обратиться или который можно изменить с помощью функций getcontext() и setcontext():

decimal.getcontext()

Возвращает текущий контекст активного потока.

decimal.setcontext(c, /)

Устанавливает c в качестве текущего контекста активного потока.

Для временного изменения активного контекста также можно использовать инструкцию with и функцию localcontext().

decimal.localcontext(ctx=None, **kwargs)

Возвращает менеджер контекста, который при входе в инструкцию with установит в качестве текущего контекста активного потока копию ctx, а при выходе из инструкции with восстановит предыдущий контекст. Если контекст не указан, используется копия текущего контекста. Аргумент kwargs используется для установки атрибутов нового контекста.

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

from decimal import localcontext

with localcontext() as ctx:
    ctx.prec = 42   # Perform a high precision calculation
    s = calculate_something()
s = +s  # Round the final result back to the default precision

С использованием именованных аргументов код будет выглядеть так:

from decimal import localcontext

with localcontext(prec=42) as ctx:
    s = calculate_something()
s = +s

Вызывает TypeError, если kwargs задаёт атрибут, который не поддерживается Context. Вызывает TypeError или ValueError, если kwargs задаёт недопустимое значение атрибута.

Изменено в версии 3.11: localcontext() теперь поддерживает установку атрибутов контекста с помощью именованных аргументов.

decimal.IEEEContext(bits)

Возвращает объект контекста, инициализированный подходящими значениями для одного из форматов обмена IEEE. Аргумент должен быть кратен 32 и меньше IEEE_CONTEXT_MAX_BITS.

Добавлено в версии 3.14.

Новые контексты также можно создавать с помощью описанного ниже конструктора Context. Кроме того, модуль предоставляет три готовых контекста:

decimal.BasicContext

Это стандартный контекст, определённый спецификацией General Decimal Arithmetic. Точность установлена равной девяти. Округление выполняется по правилу ROUND_HALF_UP. Все флаги сброшены. Все ловушки включены (обрабатываются как исключения), кроме Inexact, Rounded и Subnormal.

Поскольку включено много ловушек, этот контекст полезен для отладки.

decimal.ExtendedContext

Это стандартный контекст, определённый спецификацией General Decimal Arithmetic. Точность установлена равной девяти. Округление выполняется по правилу ROUND_HALF_EVEN. Все флаги сброшены. Ловушки не включены (поэтому во время вычислений исключения не вызываются).

Поскольку ловушки отключены, этот контекст полезен для приложений, в которых предпочтительнее получить результат NaN или Infinity, а не вызывать исключения. Это позволяет приложению завершить выполнение при наличии условий, которые в противном случае остановили бы программу.

decimal.DefaultContext

Этот контекст используется конструктором Context как шаблон для новых контекстов. Изменение поля (например, точности) приводит к изменению значения по умолчанию для новых контекстов, создаваемых конструктором Context.

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

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

Значения по умолчанию: Context.prec=28, Context.rounding=ROUND_HALF_EVEN, а ловушки для Overflow, InvalidOperation и DivisionByZero включены.

Помимо трёх предоставляемых контекстов, новые контексты можно создавать с помощью конструктора Context.

class decimal.Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)

Создаёт новый контекст. Если поле не указано или равно None, значения по умолчанию копируются из DefaultContext. Если поле flags не указано или равно None, все флаги сбрасываются.

prec

Целое число в диапазоне [1, MAX_PREC], задающее точность арифметических операций в контексте.

rounding

Одна из констант, перечисленных в разделе Режимы округления.

traps
flags

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

Emin
Emax

Целые числа, задающие допустимые верхнюю и нижнюю границы показателей степени. Emin должен находиться в диапазоне [MIN_EMIN, 0], а Emax — в диапазоне [0, MAX_EMAX].

capitals

Либо 0, либо 1 (значение по умолчанию). Если установлено значение 1, показатели степени выводятся с заглавной буквой E; в противном случае используется строчная буква e: Decimal('6.02e+23').

clamp

Либо 0 (значение по умолчанию), либо 1. Если установлено значение 1, показатель степени e экземпляра Decimal, представимого в этом контексте, строго ограничен диапазоном Emin - prec + 1 <= e <= Emax - prec + 1. Если clamp равно 0, действует более мягкое условие: скорректированный показатель степени экземпляра Decimal не превышает Emax. Если clamp равно 1, у большого нормального числа, если это возможно, уменьшается показатель степени и к коэффициенту добавляется соответствующее количество нулей, чтобы соблюсти ограничения показателя степени. Это сохраняет значение числа, но приводит к потере информации о значащих конечных нулях. Например:

>>> Context(prec=6, Emax=999, clamp=1).create_decimal('1.23e999')
Decimal('1.23000E+999')

Значение clamp 1 обеспечивает совместимость с форматами обмена десятичными числами фиксированной ширины, определёнными в IEEE 754.

Класс Context определяет несколько методов общего назначения, а также множество методов для выполнения арифметических операций непосредственно в заданном контексте. Кроме того, для каждого из описанных выше методов Decimal (за исключением методов adjusted() и as_tuple()) существует соответствующий метод Context. Например, для экземпляра Context C и экземпляра Decimal x выражение C.exp(x) эквивалентно x.exp(context=C). Каждый метод Context принимает целое число Python (экземпляр int) везде, где принимается экземпляр Decimal.

clear_flags()

Сбрасывает все флаги в значение 0.

clear_traps()

Сбрасывает все ловушки в значение 0.

Добавлено в версии 3.3.

copy()

Возвращает копию контекста.

copy_decimal(num, /)

Возвращает копию экземпляра Decimal num.

create_decimal(num='0', /)

Создаёт новый экземпляр Decimal из num, используя self в качестве контекста. В отличие от конструктора Decimal, при преобразовании применяются точность контекста, метод округления, флаги и ловушки.

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

>>> getcontext().prec = 3
>>> Decimal('3.4445') + Decimal('1.0023')
Decimal('4.45')
>>> Decimal('3.4445') + Decimal(0) + Decimal('1.0023')
Decimal('4.44')

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

create_decimal_from_float(f, /)

Создаёт новый экземпляр Decimal из числа с плавающей точкой f, выполняя округление с использованием self в качестве контекста. В отличие от метода класса Decimal.from_float(), при преобразовании применяются точность контекста, метод округления, флаги и ловушки.

>>> context = Context(prec=5, rounding=ROUND_DOWN)
>>> context.create_decimal_from_float(math.pi)
Decimal('3.1415')
>>> context = Context(prec=5, traps=[Inexact])
>>> context.create_decimal_from_float(math.pi)
Traceback (most recent call last):
    ...
decimal.Inexact: None

Добавлено в версии 3.1.

Etiny()

Возвращает значение, равное Emin - prec + 1, которое является минимальным значением показателя степени для субнормальных результатов. При возникновении потери точности показатель степени устанавливается в Etiny.

Etop()

Возвращает значение, равное Emax - prec + 1.

Обычно при работе с десятичными числами создают экземпляры Decimal, а затем применяют арифметические операции, выполняемые в текущем контексте активного потока. Альтернативный подход — использовать методы контекста для вычислений в конкретном контексте. Эти методы аналогичны методам класса Decimal и здесь рассматриваются лишь кратко.

abs(x, /)

Возвращает абсолютное значение x.

add(x, y, /)

Возвращает сумму x и y.

canonical(x, /)

Возвращает тот же объект Decimal x.

compare(x, y, /)

Сравнивает x и y по числовому значению.

compare_signal(x, y, /)

Сравнивает числовые значения двух операндов.

compare_total(x, y, /)

Сравнивает два операнда, используя их абстрактное представление.

compare_total_mag(x, y, /)

Сравнивает два операнда, используя их абстрактное представление и игнорируя знак.

copy_abs(x, /)

Возвращает копию x со знаком 0.

copy_negate(x, /)

Возвращает копию x с инвертированным знаком.

copy_sign(x, y, /)

Копирует знак y в x.

divide(x, y, /)

Возвращает результат деления x на y.

divide_int(x, y, /)

Возвращает результат деления x на y, усечённый до целого числа.

divmod(x, y, /)

Делит два числа и возвращает целую часть результата.

exp(x, /)

Возвращает e ** x.

fma(x, y, z, /)

Возвращает произведение x и y, сложенное с z.

is_canonical(x, /)

Возвращает True, если x является каноническим; в противном случае возвращает False.

is_finite(x, /)

Возвращает True, если x является конечным; в противном случае возвращает False.

is_infinite(x, /)

Возвращает True, если x является бесконечным; в противном случае возвращает False.

is_nan(x, /)

Возвращает True, если x является qNaN или sNaN; в противном случае возвращает False.

is_normal(x, /)

Возвращает True, если x является нормальным числом; в противном случае возвращает False.

is_qnan(x, /)

Возвращает True, если x является тихим NaN; в противном случае возвращает False.

is_signed(x, /)

Возвращает True, если x является отрицательным; в противном случае возвращает False.

is_snan(x, /)

Возвращает True, если x является сигнальным NaN; в противном случае возвращает False.

is_subnormal(x, /)

Возвращает True, если x является субнормальным; в противном случае возвращает False.

is_zero(x, /)

Возвращает True, если x равно нулю; в противном случае возвращает False.

ln(x, /)

Возвращает натуральный логарифм x (по основанию e).

log10(x, /)

Возвращает десятичный логарифм x (по основанию 10).

logb(x, /)

Возвращает показатель степени старшей значащей цифры модуля операнда.

logical_and(x, y, /)

Применяет логическую операцию and к соответствующим цифрам операндов.

logical_invert(x, /)

Инвертирует все цифры в x.

logical_or(x, y, /)

Применяет логическую операцию or к соответствующим цифрам операндов.

logical_xor(x, y, /)

Применяет логическую операцию xor к соответствующим цифрам операндов.

max(x, y, /)

Сравнивает два значения по числовому значению и возвращает максимальное.

max_mag(x, y, /)

Сравнивает числовые значения, игнорируя их знаки.

min(x, y, /)

Сравнивает два значения по числовому значению и возвращает минимальное.

min_mag(x, y, /)

Сравнивает числовые значения, игнорируя их знаки.

minus(x, /)

Minus соответствует унарному префиксному оператору минус в Python.

multiply(x, y, /)

Возвращает произведение x и y.

next_minus(x, /)

Возвращает наибольшее представимое число, меньшее x.

next_plus(x, /)

Возвращает наименьшее представимое число, большее x.

next_toward(x, y, /)

Возвращает число, ближайшее к x в направлении к y.

normalize(x, /)

Приводит x к простейшей форме.

number_class(x, /)

Возвращает признак класса числа x.

plus(x, /)

Plus соответствует унарному префиксному оператору плюс в Python. Эта операция применяет точность и округление контекста, поэтому она не является тождественной операцией.

power(x, y, modulo=None)

Возвращает x в степени y, при необходимости вычисляя остаток по модулю modulo.

При двух аргументах вычисляет x**y. Если x отрицательно, то y должно быть целым числом. Результат будет неточным, если только y не является целым числом, а результат — конечным и точно представимым с помощью «precision» цифр. Используется режим округления контекста. В версии на Python результаты всегда округляются правильно.

В результате Decimal(0) ** Decimal(0) получается InvalidOperation, а если InvalidOperation не перехватывается, то результатом будет Decimal('NaN').

Изменено в версии 3.3: Модуль C вычисляет power() с помощью функций exp() и ln() с правильным округлением. Результат однозначно определён, но «почти всегда округляется правильно».

При трёх аргументах вычисляет (x**y) % modulo. Для формы с тремя аргументами действуют следующие ограничения на аргументы:

  • все три аргумента должны быть целыми числами
  • y должно быть неотрицательным
  • по крайней мере одно из значений x или y должно быть ненулевым
  • modulo должно быть ненулевым и содержать не более «precision» цифр

Значение, полученное в результате Context.power(x, y, modulo), равно значению, которое было бы получено при вычислении (x**y) % modulo с неограниченной точностью, но вычисляется эффективнее. Показатель степени результата равен нулю независимо от показателей степени x, y и modulo. Результат всегда точен.

quantize(x, y, /)

Возвращает значение, равное x (с округлением) и имеющее показатель степени y.

radix()

Просто возвращает 10, поскольку это Decimal. :)

remainder(x, y, /)

Возвращает остаток от целочисленного деления.

Если результат ненулевой, его знак совпадает со знаком исходного делимого.

remainder_near(x, y, /)

Возвращает x - y * n, где n — целое число, ближайшее к точному значению x / y (если результат равен 0, его знак совпадает со знаком x).

rotate(x, y, /)

Возвращает копию x с циклическим сдвигом на y позиций.

same_quantum(x, y, /)

Возвращает True, если показатели степени обоих операндов совпадают.

scaleb(x, y, /)

Возвращает первый операнд, прибавив второе значение к его показателю степени.

shift(x, y, /)

Возвращает копию x со сдвигом на y позиций.

sqrt(x, /)

Вычисляет квадратный корень неотрицательного числа с точностью контекста.

subtract(x, y, /)

Возвращает разность x и y.

to_eng_string(x, /)

Преобразует число в строку, используя инженерную запись, если требуется показатель степени.

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

to_integral_exact(x, /)

Округляет до целого числа.

to_sci_string(x, /)

Преобразует число в строку, используя научную запись.

Константы

Константы в этом разделе относятся только к модулю C. Они также включены в версию на чистом Python для обеспечения совместимости.

32-битная

64-битная

decimal.MAX_PREC

425000000

999999999999999999

decimal.MAX_EMAX

425000000

999999999999999999

decimal.MIN_EMIN

-425000000

-999999999999999999

decimal.MIN_ETINY

-849999999

-1999999999999999997

decimal.IEEE_CONTEXT_MAX_BITS

256

512

decimal.HAVE_THREADS

Значение — True. Устарело, поскольку в Python теперь всегда есть поддержка потоков.

Устарело с версии 3.9.

decimal.HAVE_CONTEXTVAR

Значение по умолчанию — True. Если Python собран с параметром configured using the --without-decimal-contextvar option, версия на C использует контекст, локальный для потока, а не для сопрограммы, и значение равно False. В некоторых сценариях с вложенными контекстами это немного быстрее.

Добавлено в версии 3.8.3.

Режимы округления

decimal.ROUND_CEILING

Округление в направлении Infinity.

decimal.ROUND_DOWN

Округление в сторону нуля.

decimal.ROUND_FLOOR

Округление в направлении -Infinity.

decimal.ROUND_HALF_DOWN

Округление до ближайшего значения; при равном удалении — в сторону нуля.

decimal.ROUND_HALF_EVEN

Округление до ближайшего значения; при равном удалении — до ближайшего чётного целого.

decimal.ROUND_HALF_UP

Округление до ближайшего значения; при равном удалении — от нуля.

decimal.ROUND_UP

Округление от нуля.

decimal.ROUND_05UP

Округление от нуля, если последняя цифра после округления в сторону нуля была бы равна 0 или 5; в противном случае — в сторону нуля.

Сигналы

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

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

Если для сигнала включена ловушка контекста, возникновение соответствующего условия приводит к возбуждению исключения Python. Например, если включена ловушка DivisionByZero, при возникновении соответствующего условия возбуждается исключение DivisionByZero.

class decimal.Clamped

Показатель степени изменён, чтобы соответствовать ограничениям представления.

Обычно ограничение показателя степени происходит, когда он выходит за пределы ограничений контекста Emin и Emax. Если возможно, показатель степени уменьшается до допустимого значения за счёт добавления нулей к коэффициенту.

class decimal.DecimalException

Базовый класс для других сигналов и подкласс ArithmeticError.

class decimal.DivisionByZero

Сигнализирует о делении конечного числа на ноль.

Может возникать при делении, делении по модулю или возведении числа в отрицательную степень. Если этот сигнал не перехватывается, возвращается Infinity или -Infinity; знак определяется операндами вычисления.

class decimal.Inexact

Указывает, что произошло округление и результат является неточным.

Сигнал возникает, когда при округлении были отброшены ненулевые цифры. Возвращается округлённый результат. Флаг сигнала или ловушка используются для обнаружения неточных результатов.

class decimal.InvalidOperation

Выполнена недопустимая операция.

Указывает, что была запрошена операция, не имеющая смысла. Если сигнал не перехватывается, возвращается NaN. Возможные причины:

Infinity - Infinity
0 * Infinity
Infinity / Infinity
x % 0
Infinity % x
sqrt(-x) and x > 0
0 ** 0
x ** (non-integer)
x ** Infinity
class decimal.Overflow

Числовое переполнение.

Указывает, что после округления показатель степени превышает Context.Emax. Если сигнал не перехватывается, результат зависит от режима округления: он либо смещается внутрь к наибольшему представимому конечному числу, либо округляется наружу до Infinity. В обоих случаях также сигнализируются Inexact и Rounded.

class decimal.Rounded

Произошло округление, хотя информация могла и не быть потеряна.

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

class decimal.Subnormal

До округления показатель степени был меньше Emin.

Возникает, когда результат операции является субнормальным (показатель степени слишком мал). Если сигнал не перехватывается, результат возвращается без изменений.

class decimal.Underflow

Числовое исчезновение порядка, при котором результат округляется до нуля.

Возникает, когда субнормальный результат округляется до нуля. Также сигнализируются Inexact и Subnormal.

class decimal.FloatOperation

Включает более строгую семантику при смешивании чисел с плавающей точкой и Decimal.

Если сигнал не перехватывается (по умолчанию), смешивание чисел с плавающей точкой и Decimal допускается в конструкторе Decimal, методе create_decimal() и всех операторах сравнения. И преобразование, и сравнения выполняются точно. Любая смешанная операция незаметно регистрируется установкой FloatOperation во флагах контекста. Явные преобразования с помощью from_float() или create_decimal_from_float() не устанавливают этот флаг.

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

В следующей таблице представлена иерархия сигналов:

exceptions.ArithmeticError(exceptions.Exception)
    DecimalException
        Clamped
        DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
        Inexact
            Overflow(Inexact, Rounded)
            Underflow(Inexact, Rounded, Subnormal)
        InvalidOperation
        Rounded
        Subnormal
        FloatOperation(DecimalException, exceptions.TypeError)

Примечания о числах с плавающей точкой

Уменьшение ошибки округления за счёт повышения точности

Использование десятичной арифметики с плавающей точкой устраняет ошибку представления десятичных чисел (что позволяет точно представить 0.1); однако некоторые операции всё ещё могут приводить к ошибке округления, если количество ненулевых цифр превышает фиксированную точность.

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

# Examples from Seminumerical Algorithms, Section 4.2.2.
>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 8

>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.5111111')
>>> u + (v + w)
Decimal('10')

>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.01')
>>> u * (v+w)
Decimal('0.0060000')

Модуль decimal позволяет восстановить эти тождества, достаточно увеличив точность, чтобы избежать потери значимости:

>>> getcontext().prec = 20
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.51111111')
>>> u + (v + w)
Decimal('9.51111111')
>>>
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.0060000')
>>> u * (v+w)
Decimal('0.0060000')

Специальные значения

Система чисел модуля decimal предоставляет специальные значения, в том числе NaN, sNaN, -Infinity, Infinity и два нуля: +0 и -0.

Бесконечности можно создавать напрямую: Decimal('Infinity'). Они также могут возникать при делении на ноль, если сигнал DivisionByZero не перехватывается. Аналогично, если сигнал Overflow не перехватывается, бесконечность может стать результатом округления за пределами наибольшего представимого числа.

Бесконечности имеют знак (аффинны) и могут использоваться в арифметических операциях, где рассматриваются как очень большие неопределённые числа. Например, прибавление константы к бесконечности даёт другой бесконечный результат.

Некоторые операции являются неопределёнными и возвращают NaN либо возбуждают исключение, если перехватывается сигнал InvalidOperation. Например, 0/0 возвращает NaN, что означает «не число». Эта разновидность NaN является тихой и после создания распространяется на другие вычисления, всегда приводя к другому NaN. Такое поведение может быть полезным для серии вычислений, в которой иногда отсутствуют входные данные: оно позволяет продолжить вычисления, помечая определённые результаты как недопустимые.

Существует вариант sNaN, который сигнализирует об ошибке после каждой операции, а не остаётся тихим. Это полезное возвращаемое значение, когда недопустимый результат должен прервать вычисление для особой обработки.

Поведение операторов сравнения Python может показаться несколько неожиданным, если участвует NaN. Проверка на равенство, в которой один из операндов — тихий или сигнализирующий NaN, всегда возвращает False (даже при использовании Decimal('NaN')==Decimal('NaN')), тогда как проверка на неравенство всегда возвращает True. Попытка сравнить два Decimal с помощью любого из операторов <, <=, > или >= вызывает сигнал InvalidOperation, если один из операндов — NaN, и возвращает False, если этот сигнал не перехватывается. Обратите внимание, что спецификация General Decimal Arithmetic не определяет поведение прямых сравнений; эти правила для сравнений с участием NaN взяты из стандарта IEEE 854 (см. таблицу 3 в разделе 5.7). Для строгого соответствия стандартам используйте методы compare() и compare_signal().

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

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

>>> 1 / Decimal('Infinity')
Decimal('0E-1000026')

Работа с потоками

Функция getcontext() обращается к отдельному объекту Context для каждого потока. Наличие отдельных контекстов потоков позволяет потокам вносить изменения (например, getcontext().prec=10), не мешая работе других потоков.

Аналогично, функция setcontext() автоматически назначает целевой контекст текущему потоку.

Если перед вызовом getcontext() функция setcontext() не вызывалась, то getcontext() автоматически создаст новый контекст для использования в текущем потоке. Для новых объектов контекста устанавливаются значения по умолчанию из объекта decimal.DefaultContext.

Флаг sys.flags.thread_inherit_context влияет на контекст новых потоков. Если флаг имеет значение false, новые потоки начинают работу с пустым контекстом. В этом случае при вызове getcontext() создаётся новый объект контекста, использующий значения по умолчанию из DefaultContext. Если флаг имеет значение true, новые потоки начинают работу с копией контекста вызывающего потока, в котором был вызван threading.Thread.start().

Чтобы задать значения по умолчанию, которые будут использоваться всеми потоками на протяжении работы приложения, измените непосредственно объект DefaultContext. Это следует сделать до запуска любых потоков, чтобы избежать состояния гонки между потоками, вызывающими getcontext(). Например:

# Set applicationwide defaults for all threads about to be launched
DefaultContext.prec = 12
DefaultContext.rounding = ROUND_DOWN
DefaultContext.traps = ExtendedContext.traps.copy()
DefaultContext.traps[InvalidOperation] = 1
setcontext(DefaultContext)

# Afterwards, the threads can be started
t1.start()
t2.start()
t3.start()
 . . .

Примеры

Ниже приведено несколько примеров служебных функций, демонстрирующих способы работы с классом Decimal:

def moneyfmt(value, places=2, curr='', sep=',', dp='.',
             pos='', neg='-', trailneg=''):
    """Convert Decimal to a money formatted string.

    places:  required number of places after the decimal point
    curr:    optional currency symbol before the sign (may be blank)
    sep:     optional grouping separator (comma, period, space, or blank)
    dp:      decimal point indicator (comma or period)
             only specify as blank when places is zero
    pos:     optional sign for positive numbers: '+', space or blank
    neg:     optional sign for negative numbers: '-', '(', space or blank
    trailneg:optional trailing minus indicator:  '-', ')', space or blank

    >>> d = Decimal('-1234567.8901')
    >>> moneyfmt(d, curr='$')
    '-$1,234,567.89'
    >>> moneyfmt(d, places=0, sep='.', dp='', neg='', trailneg='-')
    '1.234.568-'
    >>> moneyfmt(d, curr='$', neg='(', trailneg=')')
    '($1,234,567.89)'
    >>> moneyfmt(Decimal(123456789), sep=' ')
    '123 456 789.00'
    >>> moneyfmt(Decimal('-0.02'), neg='<', trailneg='>')
    '<0.02>'

    """
    q = Decimal(10) ** -places      # 2 places --> '0.01'
    sign, digits, exp = value.quantize(q).as_tuple()
    result = []
    digits = list(map(str, digits))
    build, next = result.append, digits.pop
    if sign:
        build(trailneg)
    for i in range(places):
        build(next() if digits else '0')
    if places:
        build(dp)
    if not digits:
        build('0')
    i = 0
    while digits:
        build(next())
        i += 1
        if i == 3 and digits:
            i = 0
            build(sep)
    build(curr)
    build(neg if sign else pos)
    return ''.join(reversed(result))

def pi():
    """Compute Pi to the current precision.

    >>> print(pi())
    3.141592653589793238462643383

    """
    getcontext().prec += 2  # extra digits for intermediate steps
    three = Decimal(3)      # substitute "three=3.0" for regular floats
    lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
    while s != lasts:
        lasts = s
        n, na = n+na, na+8
        d, da = d+da, da+32
        t = (t * n) / d
        s += t
    getcontext().prec -= 2
    return +s               # unary plus applies the new precision

def exp(x):
    """Return e raised to the power of x.  Result type matches input type.

    >>> print(exp(Decimal(1)))
    2.718281828459045235360287471
    >>> print(exp(Decimal(2)))
    7.389056098930650227230427461
    >>> print(exp(2.0))
    7.38905609893
    >>> print(exp(2+0j))
    (7.38905609893+0j)

    """
    getcontext().prec += 2
    i, lasts, s, fact, num = 0, 0, 1, 1, 1
    while s != lasts:
        lasts = s
        i += 1
        fact *= i
        num *= x
        s += num / fact
    getcontext().prec -= 2
    return +s

def cos(x):
    """Return the cosine of x as measured in radians.

    The Taylor series approximation works best for a small value of x.
    For larger values, first compute x = x % (2 * pi).

    >>> print(cos(Decimal('0.5')))
    0.8775825618903727161162815826
    >>> print(cos(0.5))
    0.87758256189
    >>> print(cos(0.5+0j))
    (0.87758256189+0j)

    """
    getcontext().prec += 2
    i, lasts, s, fact, num, sign = 0, 0, 1, 1, 1, 1
    while s != lasts:
        lasts = s
        i += 2
        fact *= i * (i-1)
        num *= x * x
        sign *= -1
        s += num / fact * sign
    getcontext().prec -= 2
    return +s

def sin(x):
    """Return the sine of x as measured in radians.

    The Taylor series approximation works best for a small value of x.
    For larger values, first compute x = x % (2 * pi).

    >>> print(sin(Decimal('0.5')))
    0.4794255386042030002732879352
    >>> print(sin(0.5))
    0.479425538604
    >>> print(sin(0.5+0j))
    (0.479425538604+0j)

    """
    getcontext().prec += 2
    i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1
    while s != lasts:
        lasts = s
        i += 2
        fact *= i * (i-1)
        num *= x * x
        sign *= -1
        s += num / fact * sign
    getcontext().prec -= 2
    return +s

Часто задаваемые вопросы о Decimal

В: Вводить decimal.Decimal('1234.5') неудобно. Можно ли сократить ввод при работе в интерактивном интерпретаторе?

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

>>> D = decimal.Decimal
>>> D('1.23') + D('3.45')
Decimal('4.68')

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

О: Метод quantize() округляет число до фиксированного количества десятичных знаков. Если включена ловушка Inexact, этот метод также удобно использовать для проверки:

>>> TWOPLACES = Decimal(10) ** -2       # same as Decimal('0.01')
>>> # Round to two places
>>> Decimal('3.214').quantize(TWOPLACES)
Decimal('3.21')
>>> # Validate that a number does not exceed two places
>>> Decimal('3.21').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Decimal('3.21')
>>> Decimal('3.214').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Traceback (most recent call last):
   ...
Inexact: None

В: Как поддерживать инвариант, если входные значения с двумя десятичными знаками уже проверены?

О: Некоторые операции, например сложение, вычитание и умножение на целое число, автоматически сохраняют фиксированную точку. Другие операции, например деление и умножение на нецелое число, изменяют количество десятичных знаков, поэтому после них необходимо выполнить шаг quantize():

>>> a = Decimal('102.72')           # Initial fixed-point values
>>> b = Decimal('3.17')
>>> a + b                           # Addition preserves fixed-point
Decimal('105.89')
>>> a - b
Decimal('99.55')
>>> a * 42                          # So does integer multiplication
Decimal('4314.24')
>>> (a * b).quantize(TWOPLACES)     # Must quantize non-integer multiplication
Decimal('325.62')
>>> (b / a).quantize(TWOPLACES)     # And quantize division
Decimal('0.03')

При разработке приложений с фиксированной точкой удобно определять функции для выполнения шага quantize():

>>> def mul(x, y, fp=TWOPLACES):
...     return (x * y).quantize(fp)
...
>>> def div(x, y, fp=TWOPLACES):
...     return (x / y).quantize(fp)
>>> mul(a, b)                       # Automatically preserve fixed-point
Decimal('325.62')
>>> div(b, a)
Decimal('0.03')

В: Одно и то же значение можно выразить разными способами. Числа 200, 200.000, 2E2 и .02E+4 имеют одно значение при разной точности. Можно ли преобразовать их в одно узнаваемое каноническое значение?

О: Метод normalize() отображает все эквивалентные значения в одно представительное значение:

>>> values = map(Decimal, '200 200.000 2E2 .02E+4'.split())
>>> [v.normalize() for v in values]
[Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2')]

В: Когда в ходе вычисления происходит округление?

О: Оно происходит после вычисления. Согласно принципу, лежащему в основе спецификации decimal, числа считаются точными и создаются независимо от текущего контекста. Их точность может даже превышать точность текущего контекста. Вычисления выполняются с этими точными входными данными, а затем округление (или другие операции контекста) применяется к результату вычисления:

>>> getcontext().prec = 5
>>> pi = Decimal('3.1415926535')   # More than 5 digits
>>> pi                             # All digits are retained
Decimal('3.1415926535')
>>> pi + 0                         # Rounded after an addition
Decimal('3.1416')
>>> pi - Decimal('0.00005')        # Subtract unrounded numbers, then round
Decimal('3.1415')
>>> pi + 0 - Decimal('0.00005').   # Intermediate values are rounded
Decimal('3.1416')

В: Некоторые десятичные значения всегда выводятся в экспоненциальной записи. Можно ли представить их без экспоненты?

О: Для некоторых значений экспоненциальная запись — единственный способ указать количество значащих разрядов в коэффициенте. Например, представление 5.0E+3 в виде 5000 сохраняет значение, но не позволяет показать исходную точность в два десятичных знака.

Если приложению не нужно отслеживать точность, можно легко убрать показатель степени и конечные нули, потеряв точность, но сохранив значение:

>>> def remove_exponent(d):
...     return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')

В: Можно ли преобразовать обычное число с плавающей точкой в Decimal?

О: Да, любое двоичное число с плавающей точкой можно точно представить как Decimal, хотя для точного преобразования может потребоваться гораздо большая точность, чем можно предположить:

>>> Decimal(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875')

В: Как при выполнении сложных вычислений убедиться, что результат не является ошибочным из-за недостаточной точности или аномалий округления?

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

В: Я заметил, что точность контекста применяется к результатам операций, но не к входным данным. Есть ли что-то, о чём следует помнить при смешивании значений с разной точностью?

О: Да. Принцип состоит в том, что все значения считаются точными, как и арифметические операции над ними. Округляются только результаты. Преимущество для входных данных заключается в том, что «получаешь именно то, что вводишь». Недостаток в том, что результаты могут выглядеть странно, если забыть, что входные данные не были округлены:

>>> getcontext().prec = 3
>>> Decimal('3.104') + Decimal('2.104')
Decimal('5.21')
>>> Decimal('3.104') + Decimal('0.000') + Decimal('2.104')
Decimal('5.20')

Решение — либо увеличить точность, либо принудительно округлить входные данные с помощью унарного оператора плюс:

>>> getcontext().prec = 3
>>> +Decimal('1.23456789')      # unary plus triggers rounding
Decimal('1.23')

Кроме того, входные данные можно округлить при создании с помощью метода Context.create_decimal():

>>> Context(prec=5, rounding=ROUND_DOWN).create_decimal('1.2345678')
Decimal('1.2345')

В: Реализация CPython быстро работает с большими числами?

О: Да. В реализациях CPython и PyPy3 версии модуля decimal на C/CFFI используют высокоскоростную библиотеку libmpdec для арифметики с десятичными числами произвольной точности и корректным округлением [1]. libmpdec использует умножение Карацубы для чисел среднего размера и числовое теоретическое преобразование для очень больших чисел.

Для точной арифметики произвольной точности необходимо настроить контекст. Значения Emin и Emax всегда должны быть максимальными, а clamp всегда должен быть равен 0 (значение по умолчанию). Задавать prec следует осторожно.

Самый простой способ попробовать арифметику с большими числами — установить максимальное значение prec [2]:

>>> setcontext(Context(prec=MAX_PREC, Emax=MAX_EMAX, Emin=MIN_EMIN))
>>> x = Decimal(2) ** 256
>>> x / 128
Decimal('904625697166532776746648320380374280103671755200316906558262375061821325312')

Для неточных результатов MAX_PREC слишком велико на 64-битных платформах, и доступной памяти будет недостаточно:

>>> Decimal(1) / 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError

В системах с избыточным выделением памяти (например, Linux) более продвинутый подход состоит в том, чтобы установить значение prec в соответствии с объёмом доступной оперативной памяти. Предположим, у вас 8 ГБ оперативной памяти и ожидается 10 одновременных операндов, каждому из которых требуется не более 500 МБ:

>>> import sys
>>>
>>> # Maximum number of digits for a single operand using 500MB in 8-byte words
>>> # with 19 digits per word (4-byte and 9 digits for the 32-bit build):
>>> maxdigits = 19 * ((500 * 1024**2) // 8)
>>>
>>> # Check that this works:
>>> c = Context(prec=maxdigits, Emax=MAX_EMAX, Emin=MIN_EMIN)
>>> c.traps[Inexact] = True
>>> setcontext(c)
>>>
>>> # Fill the available precision with nines:
>>> x = Decimal(0).logical_invert() * 9
>>> sys.getsizeof(x)
524288112
>>> x + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  decimal.Inexact: [<class 'decimal.Inexact'>]

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

[1]

Добавлено в версии 3.3.

[2]

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

© 2001 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/library/decimal.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API