Spec-Zone.ru › Python 3.13

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')

Для 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. Однако для сравнения экземпляра Decimal x с другим числом y можно использовать операторы сравнения Python. Это позволяет избежать неоднозначных результатов при сравнении на равенство чисел разных типов.

Изменено в версии 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.

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 используется для задания атрибутов нового контекста.

Например, следующий код задаёт текущую точность Decimal равной 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() теперь поддерживает установку атрибутов контекста с помощью именованных аргументов.

Новые контексты также можно создавать с помощью описанного ниже конструктора 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. Слева от десятичной точки может оставаться до трёх цифр; также может потребоваться добавить один или два конечных нуля.

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.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() автоматически создаст новый контекст для использования в текущем потоке.

Новый контекст копируется из прототипа, называемого DefaultContext. Чтобы управлять значениями по умолчанию и обеспечить использование одинаковых значений каждым потоком на протяжении всего приложения, измените непосредственно объект 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')]

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

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

>>> 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–2025 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/library/decimal.html

Spec-Zone.ru

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