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 предпочтительнее в приложениях бухгалтерского учёта, которые имеют строгие инварианты равенства. - Модуль decimal включает понятие значащих цифр, так что
1.30 + 1.20равно2.50. Завершающий ноль сохраняется для обозначения значимости. Это обычное представление для приложений, связанных с деньгами. При умножении подход «школьной арифметики» использует все цифры в множителях. Например,1.3 * 1.2даёт1.56, а1.30 * 1.20даёт1.5600. -
В отличие от основанной на аппаратуре двоичной плавающей точки, модуль decimal имеет изменяемую пользователем точность (по умолчанию 28 знаков), которая может быть сколь угодно большой для данной задачи:
>>> from decimal import * >>> getcontext().prec = 6 >>> Decimal(1) / Decimal(7) Decimal('0.142857') >>> getcontext().prec = 28 >>> Decimal(1) / Decimal(7) Decimal('0.1428571428571428571428571429') - Как двоичная, так и десятичная плавающая точка реализуются на основе опубликованных стандартов. В то время как встроенный тип float раскрывает лишь небольшую часть своих возможностей, модуль decimal раскрывает все необходимые части стандарта. При необходимости программист имеет полный контроль над округлением и обработкой сигналов. Это включает возможность принудительного выполнения точной арифметики путём использования исключений для блокирования любых неточных операций.
- Модуль decimal был разработан, чтобы поддерживать «без предубеждения, как точную неокруглённую десятичную арифметику (иногда называемую арифметикой с фиксированной точкой), так и округлённую арифметику с плавающей точкой» — отрывок из спецификации десятичной арифметики.
Архитектура модуля сосредоточена вокруг трёх концепций: десятичного числа, контекста арифметики и сигналов.
Десятичное число неизменяемо. Оно имеет знак, коэффициентные цифры и показатель степени. Для сохранения значимости коэффициентные цифры не обрезают завершающие нули. Десятичные числа также включают специальные значения, такие как Infinity, -Infinity, и NaN. Стандарт также различает -0 от +0.
Контекст арифметики — это среда, определяющая точность, правила округления, ограничения по показателям степени, флаги, указывающие результаты операций, и обработчики сигналов, которые определяют, рассматриваются ли сигналы как исключения. Опции округления включают ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_UP и ROUND_05UP.
Сигналы — это группы исключительных условий, возникающих в ходе вычислений. В зависимости от потребностей приложения сигналы могут быть проигнорированы, рассмотрены как информационные или обработаны как исключения. Сигналы в модуле decimal: Clamped, InvalidOperation, DivisionByZero, Inexact, Rounded, Subnormal, Overflow, Underflow и FloatOperation.
Для каждого сигнала есть флаг и обработчик. При возникновении сигнала его флаг устанавливается в единицу, а затем, если обработчик сигнала установлен в единицу, генерируется исключение. Флаги сохраняются, поэтому пользователю необходимо сбросить их перед мониторингом вычисления.
См. также
- Спецификация IBM General Decimal Arithmetic, Спецификация General Decimal Arithmetic.
Быстрый старт
Обычно работа с десятичными числами начинается с импорта модуля, просмотра текущего контекста с помощью 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.
Объекты 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 для сравнения экземпляраDecimalxс другим числом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 для NaN.
Добавлена в версии 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_signed() -
Возвращает
True, если аргумент имеет отрицательный знак, иFalseв противном случае. Обратите внимание, что нули и NaN могут иметь знаки.
-
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 (Not a Number). -
"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.Эта операция не зависит от контекста и выполняется без ошибок: флаги не изменяются, округление не выполняется. В качестве исключения, версия C может вызвать InvalidOperation, если второй операнд не может быть преобразован точно.
-
scaleb(other, context=None) -
Возвращает первый операнд с экспонентой, скорректированной вторым. Эквивалентно возвращает первый операнд, умноженный на
10**other. Второй операнд должен быть целым числом.
-
shift(other, context=None) -
Возвращает результат сдвига цифр первого операнда на величину, указанную вторым операндом. Второй операнд должен быть целым числом в диапазоне от -precision до precision. Абсолютное значение второго операнда задаёт количество позиций для сдвига. Если второй операнд положительный, сдвиг выполняется влево; в противном случае — вправо. Цифры, смещённые в коэффициент, заполняются нулями. Знак и экспонента первого операнда остаются неизменными.
-
sqrt(context=None) -
Возвращает квадратный корень аргумента с полной точностью.
-
to_eng_string(context=None) -
Преобразует в строку, используя инженерную нотацию, если необходима экспонента.
Инженерная нотация имеет экспоненту, кратную 3. Это может оставить до 3 цифр слева от десятичной точки и может потребовать добавления одной или двух последующих нулей.
Например, это преобразует
Decimal('123E+1')вDecimal('1.23E+3').
-
to_integral(rounding=None, context=None) -
Идентично методу
to_integral_value(). Имяto_integralсохранено для совместимости со старыми версиями.
-
to_integral_exact(rounding=None, context=None) -
Округляет до ближайшего целого числа, сигнализируя о
InexactилиRounded, если происходит округление. Режим округления определяется параметромrounding, если он задан, иначе — заданным значениемcontext. Если ни один параметр не задан, используется режим округления текущего контекста.
-
Логические операнды
Методы 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) -
Возвращает менеджер контекста, который установит текущий контекст для активной нити в копию 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. Например, для экземпляра классаContextCи экземпляра классаDecimalx,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) -
Возвращает показатель степени величины MSD операнда.
-
logical_and(x, y) -
Применяет логическую операцию and к каждой паре цифр операндов.
-
logical_invert(x) -
Инвертирует все цифры в x.
-
logical_or(x, y) -
Применяет логическую операцию or к каждой паре цифр операндов.
-
logical_xor(x, y) -
Применяет логическую операцию xor к каждой паре цифр операндов.
-
max(x, y) -
Сравнивает два значения численно и возвращает максимальное.
-
max_mag(x, y) -
Сравнивает значения численно, игнорируя знак.
-
min(x, y) -
Сравнивает два значения численно и возвращает минимальное.
-
min_mag(x, y) -
Сравнивает значения численно, игнорируя знак.
-
minus(x) -
Оператор унарного минуса соответствует оператору унарного префиксного минуса в 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) -
Оператор унарного плюса соответствует оператору унарного префиксного плюса в Python. Эта операция применяется к точности и округлениям контекста, поэтому это не тождественная операция.
-
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) -
Преобразует число в строку, используя научную нотацию.
-
Постоянные
Постоянные в этом разделе относятся только к модулю C. Они также включены в чистую версию Python для совместимости.
32-битный | 64-битный | |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
-
decimal.HAVE_THREADS -
Значение равно
True. Устарело, так как в Python всегда есть потоки.
Устарело начиная с версии 3.9.
-
decimal.HAVE_CONTEXTVAR -
Значение по умолчанию равно
True. Если Python скомпилирован--without-decimal-contextvar, версия C использует контекст потока, а не корутину, и значение равноFalse. Это немного быстрее в некоторых сценариях вложенного контекста.
Добавлен в версии 3.9: перенос назад в 3.7 и 3.8
Режимы округления
-
decimal.ROUND_CEILING -
Округление в сторону
Infinity.
-
decimal.ROUND_DOWN -
Округление к нулю.
-
decimal.ROUND_FLOOR -
Округление в сторону
-Infinity.
-
decimal.ROUND_HALF_DOWN -
Округление к ближайшему с предпочтением к нулю при равенстве.
-
decimal.ROUND_HALF_EVEN -
Округление к ближайшему с предпочтением к ближайшему четному числу при равенстве.
-
decimal.ROUND_HALF_UP -
Округление к ближайшему с предпочтением от нуля при равенстве.
-
decimal.ROUND_UP -
Округление от нуля.
-
decimal.ROUND_05UP -
Округлять от нуля, если последняя цифра после округления к нулю была бы 0 или 5; в противном случае округлять к нулю.
Сигналы
Сигналы представляют собой условия, возникающие во время вычислений. Каждый соответствует одному флагу контекста и одному флагу разрешения перехвата контекста.
Флаг контекста устанавливается всякий раз, когда встречается условие. После вычисления флаги могут быть проверены в информационных целях (например, чтобы определить, было ли вычисление точным). После проверки флагов убедитесь, что все флаги очищены перед началом следующего вычисления.
Если флаг разрешения перехвата контекста установлен для сигнала, то условие вызывает поднятие исключения Python. Например, если установлен флаг перехвата DivisionByZero, то исключение DivisionByZero поднимается при обнаружении условия.
-
class decimal.Clamped -
Изменён порядок для соответствия ограничениям представления.
Обычно ограничение происходит, когда показатель степени выходит за пределы ограничений контекста
EminиEmax. Если возможно, показатель степени уменьшается для соответствия путём добавления нулей к коэффиценту.
-
class decimal.DecimalException -
Базовый класс для других сигналов и подкласс
ArithmeticError.
-
class decimal.DivisionByZero -
Сигнализирует о делении ненулевого числа на ноль.
Может возникнуть при делении, модульном делении или при возведении числа в отрицательную степень. Если этот сигнал не перехвачен, возвращает
Infinityили-Infinityсо знаком, определяемым входными данными вычисления.
-
class decimal.Inexact -
Указывает на то, что произошло округление, и результат не точный.
Сигнализирует, когда при округлении были отброшены ненулевые цифры. Возвращается округленный результат. Флаг сигнала или перехват используются для обнаружения случаев, когда результаты не являются точными.
-
class decimal.InvalidOperation -
Была выполнена недопустимая операция.
Указывает на то, что была запрошена операция, которая не имеет смысла. Если не перехвачено, возвращает
NaN. Возможные причины:Infinity - Infinity 0 * Infinity Infinity / Infinity x % 0 Infinity % x sqrt(-x) and x > 0 0 ** 0 x ** (non-integer) x ** Infinity
-
class decimal.Overflow -
Переполнение.
Указывает, что показатель степени больше
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 FAQ
В. Ввод 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')
В. Быстра ли реализация CPython для больших чисел?
О. Да. В реализациях CPython и PyPy3, C/CFFI версии модуля decimal интегрируют высокопроизводительную библиотеку libmpdec для арифметики десятичных чисел с произвольной точностью и правильным округлением с плавающей точкой. libmpdec использует умножение Карацубы для средних чисел и преобразование по теореме о числе для очень больших чисел. Однако, чтобы получить эти преимущества производительности, необходимо установить контекст для вычислений без округления.
>>> c = getcontext() >>> c.prec = MAX_PREC >>> c.Emax = MAX_EMAX >>> c.Emin = MIN_EMIN
Введено в версии 3.3.
© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.7/library/decimal.html