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

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


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

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

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

  • Точность переносится на арифметику. В десятичной системе счисления с плавающей запятой 0.1 + 0.1 + 0.1 - 0.3 в точности равно нулю. В двоичной системе счисления с плавающей запятой результат равен 5.5511151231257827e-017. При приближении к нулю различия препятствуют надежной проверке на равенство и могут накапливаться. По этой причине десятичная дробь предпочтительнее в бухгалтерских приложениях, которые имеют строгие инварианты равенства.

  • Десятичный модуль включает в себя представление о значащих позициях, так что 1.30 + 1.20 равно 2.50. Конечный ноль сохраняется для указания значимости. Это обычное представление для приложений, работающих с денежными средствами. Для умножения в «школьном учебнике» используются все цифры, входящие в состав множимых. Например, 1.3 * 1.2 дает 1.56, а 1.30 * 1.20 - 1.5600.

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

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

  • Модуль 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.

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

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

См.также

Краткое руководство по началу работы

Обычно использование десятичных дробей начинается с импорта модуля, просмотра текущего контекста с помощью 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

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

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

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

И некоторые математические функции также доступны для десятичной системы счисления.:

>>> 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 показывает, что рациональное приближение к pi было округлено (цифры, превышающие точность контекста, были отброшены) и что результат неточен (некоторые из отброшенных цифр были отличны от нуля).

Отдельные ловушки устанавливаются с помощью словаря в атрибуте 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.

Десятичные объекты

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

Создайте новый объект Decimal на основе значения *.

значением может быть целое число, строка, кортеж, float или другой объект Decimal. Если значение не задано, возвращает 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 указано выше. К ним относятся десятичные цифры из различных других алфавитов (например, арабо-индийские цифры и цифры Деванагари), а также цифры полной ширины от '\uff10' до '\uff19'.

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

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

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

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

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

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

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

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

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

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

>>> (-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 (соответственно), как описано в спецификации.

Десятичные объекты, как правило, нельзя комбинировать с числами с плавающей запятой или экземплярами 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 для бесконечностей и ValueError для NANS.

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

as_tuple()

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

canonical()

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

compare(other, context=None)

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

compare_total_mag(other, context=None)

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

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

conjugate()

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

copy_abs()

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

copy_negate()

Возвращает отрицание аргумента. Контекст не влияет на эту операцию, и она выполняется автоматически: флажки не меняются, округление не выполняется.

copy_sign(other, context=None)

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

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

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

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

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

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

Если показатель степени второго операнда больше, чем у первого, то может потребоваться округление. В этом случае режим округления определяется аргументом 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)

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

same_quantum(other, context=None)

Проверьте, имеют ли self и other одинаковый показатель или оба они равны NaN.

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

scaleb(other, context=None)

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

shift(other, context=None)

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

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

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

Методы 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)

Возвращает диспетчер контекста, который устанавливает текущий контекст для активного потока в качестве копии ctx при входе в with-statement и восстанавливает предыдущий контекст при выходе из with-statement. Если контекст не указан, используется копия текущего контекста. Аргумент 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() теперь поддерживается настройка атрибутов контекста с помощью аргументов ключевых слов.

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

class decimal.BasicContext

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

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

class decimal.ExtendedContext

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

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

class 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 Modes.

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

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

Поле заглавные буквы имеет значение либо 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')

Фиксированное значение 1 обеспечивает совместимость с десятичными форматами обмена с фиксированной шириной, указанными в IEEE 754.

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

clear_flags()

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

clear_traps()

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

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

copy()

Возвращает дубликат контекста.

copy_decimal(num)

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

create_decimal(num)

Создает новый десятичный экземпляр из 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)

Создает новый десятичный экземпляр из числа с плавающей запятой 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)

Возвращает тот же десятичный объект 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)

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

log10(x)

Возвращает логарифм x по основанию 10.

logb(x)

Возвращает показатель степени величины операндов MSD.

logical_and(x, y)

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

logical_invert(x)

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

logical_or(x, y)

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

logical_xor(x, y)

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

max(x, y)

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

max_mag(x, y)

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

min(x, y)

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

min_mag(x, y)

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

minus(x)

Minus соответствует унарному префиксному оператору 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 соответствует оператору 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 должно быть ненулевым и содержать не более цифр «точности»

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

quantize(x, y)

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

radix()

Просто возвращает 10, так как это десятичное число, :)

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)

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

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.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; в противном случае округлите в сторону нуля.

Сигналы

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

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

Если для сигнала установлен параметр contexts trap enabler, то условие вызывает возникновение исключения 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, 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. Попытка сравнить две десятичные дроби с помощью любого из операторов <, <=, > или >= вызовет сигнал InvalidOperation, если любой из операндов является NaN, и верните False, если этот сигнал не перехвачен. Обратите внимание, что общая спецификация десятичной арифметики не определяет поведение прямых сравнений; эти правила для сравнений, включающих NaN, были взяты из стандарта IEEE 854 (см. таблицу 3 в разделе 5.7). Чтобы обеспечить строгое соответствие стандартам, используйте вместо этого методы compare() и compare_signal().

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

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

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

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

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

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

Если setcontext() не вызывался ранее getcontext(), то 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('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(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875')

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

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

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

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

>>> 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 для CCF FI интегрируют высокоскоростную библиотеку libmpdec для арифметики с плавающей запятой произвольной точности с правильным округлением в десятичной системе счисления [1]. libmpdec использует Karatsuba multiplication для вычислений среднего размера. числа и Number Theoretic Transform для очень больших чисел.

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

Самый простой способ опробовать арифметику bignum - это использовать максимальное значение для 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, если ожидается, что все вычисления будут точными.

Вернуться на верх