Spec-Zone.ru › Python 3.6

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.

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

См. также

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

9.4.1. Быстрый учебник

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

9.4.2. Объекты 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

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

Если value является tuple, он должен содержать три компонента: знак (0 для положительного или 1 для отрицательного), кортеж цифр и целое число экспоненты. Например, 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. Применяются все обычные математические операции и специальные методы. Аналогично, объекты десятичной с плавающей точкой можно копировать, сохранять в виде пикла, печатать, использовать в качестве ключей словарей, элементов множеств, сравнивать, сортировать и приводить к другому типу (например, float или int).

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

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

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

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

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

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

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

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

adjusted()

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

as_integer_ratio()

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

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

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

Новое в версии 3.6.

as_tuple()

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

canonical()

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

compare(other, context=None)

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

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

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

compare_total(other, context=None)

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

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

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

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

compare_total_mag(other, context=None)

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

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

conjugate()

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

copy_abs()

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

copy_negate()

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

copy_sign(other, context=None)

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

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

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

exp(context=None)

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

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

Метод класса, преобразующий число с плавающей точкой в десятичное число точно.

Обратите внимание, что 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)

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

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. Это гарантирует, что, если нет условия ошибки, порядок quantized всегда равен порядку правого операнда.

Также в отличие от других операций, 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.

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

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

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

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

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

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

decimal.getcontext()

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

decimal.setcontext(c)

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

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

decimal.localcontext(ctx=None)

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

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

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

class decimal.BasicContext

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

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

class decimal.ExtendedContext

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

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

class decimal.DefaultContext

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

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

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

Значения по умолчанию: prec=28, 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)

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

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

log10(x)

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

logb(x)

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

logical_and(x, y)

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

logical_invert(x)

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

logical_or(x, y)

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

logical_xor(x, y)

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

max(x, y)

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

max_mag(x, y)

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

min(x, y)

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

min_mag(x, y)

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

minus(x)

Оператор унарного минуса.

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)

Оператор унарного плюса. Применяет точность и правила округления контекста, поэтому это не тождественная операция.

power(x, y, modulo=None)

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

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

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

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

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

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

quantize(x, y)

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

radix()

Просто возвращает 10, так как это Decimal, :)

remainder(x, y)

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

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

remainder_near(x, y)

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

rotate(x, y)

Возвращает повернутую копию x на y позиций.

same_quantum(x, y)

Возвращает True, если у двух операндов одинаковый показатель степени.

scaleb(x, y)

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

shift(x, y)

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

sqrt(x)

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

subtract(x, y)

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

to_eng_string(x)

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

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

to_integral_exact(x)

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

to_sci_string(x)

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

9.4.4. Константы

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

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

decimal.ROUND_CEILING

Округление вверх.

decimal.ROUND_DOWN

Округление к нулю.

decimal.ROUND_FLOOR

Округление вниз.

decimal.ROUND_HALF_DOWN

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

decimal.ROUND_HALF_EVEN

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

decimal.ROUND_HALF_UP

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

decimal.ROUND_UP

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

decimal.ROUND_05UP

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

9.4.6. Сигналы

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

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

Если в контексте установлен разрешающий бит для сигнала, то это условие вызывает исключение 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

Переполнение числа.

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

class decimal.Rounded

Произошло округление, хотя возможно, что информация не потеряна.

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

class decimal.Subnormal

Порядок величины был ниже Emin до округления.

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

class decimal.Underflow

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

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

class decimal.FloatOperation

Включить более строгие семантики для смешивания чисел с плавающей точкой и Decimals.

Если сигнал не перехватывается (по умолчанию), смешивание чисел с плавающей точкой и Decimals разрешено в конструкторе 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)

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

9.4.7.1. Уменьшение ошибки округления при увеличении точности

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

9.4.7.2. Особые значения

Система чисел для модуля 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, если этот сигнал не перехватывается. Обратите внимание, что Спецификация общего десятичного арифметического не указывает поведение прямых сравнений; эти правила сравнений, включающих NaN, взяты из стандарта IEEE 854 (см. таблицу 3 в разделе 5.7). Для обеспечения строгого соответствия стандартам используйте методы compare() и compare-signal() вместо этого.

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

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

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

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

Функция 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()
 . . .

9.4.9. Примеры использования

Ниже приведены несколько примеров, которые служат вспомогательными функциями и демонстрируют способы работы с классом 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

9.4.10. Вопросы и ответы по 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')]

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

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

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

Spec-Zone.ru

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