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 общей десятичной арифметики, Спецификация общей десятичной арифметики.
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.
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
Также допускаются другие десятичные цифры Юникода, где
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установлена. По умолчанию ловушка выключена.Объекты десятичной плавающей запятой обладают многими свойствами других встроенных числовых типов, таких как
floatиint. Все обычные математические операции и специальные методы применяются. Аналогично, объекты decimal можно копировать, сериализовать, выводить на печать, использовать в качестве ключей словарей, элементов множеств, сравнивать, сортировать и преобразовывать в другой тип (например,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_tuple() -
Возвращает представление числа в виде именованного кортежа:
DecimalTuple(sign, digits, exponent).
-
canonical() -
Возвращает каноническое представление аргумента. В настоящее время представление экземпляра
Decimalвсегда каноническое, поэтому эта операция возвращает его аргумент без изменений.
-
compare(other, context=None) -
Сравнивает значения двух экземпляров Decimal.
compare()возвращает экземпляр Decimal, а если какой-либо операнд — NaN, то результатом является NaN:a or b is a NaN ==> Decimal('NaN') a < b ==> Decimal('-1') a == b ==> Decimal('0') a > b ==> Decimal('1')
-
compare_signal(other, context=None) -
Эта операция идентична методу
compare(), за исключением того, что все NaN сигнализируют. То есть, если ни один операнд не является сигнализирующим NaN, любой тихий NaN операнд обрабатывается так, как если бы он был сигнализирующим NaN.
-
compare_total(other, context=None) -
Сравнивает два операнда, используя их абстрактное представление, а не их числовое значение. Аналогично методу
compare(), но результат дает полное упорядочение экземпляровDecimal. Два экземпляраDecimalс одинаковым числовым значением, но разными представлениями, сравниваются как неравные в этом порядке:>>> Decimal('12.0').compare_total(Decimal('12')) Decimal('-1')Тихие и сигнализирующие NaN также включены в полное упорядочение. Результат этой функции —
Decimal('0')если у обоих операндов одинаковое представление,Decimal('-1')если первый операнд ниже по полному порядку, чем второй, иDecimal('1')если первый операнд выше по полному порядку, чем второй операнд. Подробности полного порядка см. в спецификации.Эта операция не зависит от контекста и не вызывает сигнализацию: флаги не изменяются и округление не выполняется. В качестве исключения, C-версия может генерировать InvalidOperation, если второй операнд не может быть преобразован точно.
-
compare_total_mag(other, context=None) -
Сравнивает два операнда, используя их абстрактное представление, а не их значение, как в
compare_total(), но игнорируя знак каждого операнда.x.compare_total_mag(y)эквивалентноx.copy_abs().compare_total(y.copy_abs()).Эта операция не зависит от контекста и не вызывает сигнализацию: флаги не изменяются и округление не выполняется. В качестве исключения, C-версия может генерировать InvalidOperation, если второй операнд не может быть преобразован точно.
-
conjugate() -
Просто возвращает self, этот метод нужен только для соответствия спецификации Decimal.
-
copy_abs() -
Возвращает абсолютное значение аргумента. Эта операция не зависит от контекста и не вызывает сигнализацию: флаги не изменяются и округление не выполняется.
-
copy_negate() -
Возвращает отрицание аргумента. Эта операция не зависит от контекста и не вызывает сигнализацию: флаги не изменяются и округление не выполняется.
-
copy_sign(other, context=None) -
Возвращает копию первого операнда со знаком, установленным в соответствии со знаком второго операнда. Например:
>>> Decimal('2.3').copy_sign(Decimal('-1.5')) Decimal('-2.3')Эта операция не зависит от контекста и не вызывает сигнализацию: флаги не изменяются и округление не выполняется. В качестве исключения, C-версия может генерировать InvalidOperation, если второй операнд не может быть преобразован точно.
-
exp(context=None) -
Возвращает значение функции (натурального) экспоненциального
e**xв заданном числе. Результат округляется с использованием режима округленияROUND_HALF_EVEN.>>> Decimal(1).exp() Decimal('2.718281828459045235360287471') >>> Decimal(321).exp() Decimal('2.561702493119680037517373933E+139')
-
-
from_float(f) -
Метод класса, преобразующий число с плавающей запятой в десятичное число точно.
Обратите внимание, что
Decimal.from_float(0.1)не то же самое, чтоDecimal(‘0.1’). Поскольку 0,1 не может быть точно представлено в двоичной системе с плавающей запятой, значение хранится как ближайшее представимое значение, которое равно0x1.999999999999ap-4. Эквивалентное значение в десятичной системе равно0.1000000000000000055511151231257827021181583404541015625.>>> 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_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. Если ни один параметр не задан, используется режим округления текущего контекста.
-
2.1. Логические операнды
Методы logical_and(), logical_invert(), logical_or(), и logical_xor() ожидают в качестве аргументов логические операнды. Логический операнд — это экземпляр Decimal, у которого экспонента и знак равны нулю, а все цифры равны либо 0 , либо 1.
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. Например, для экземпляра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) -
Возвращает десятичный логарифм от 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) -
Отрицание соответствует унарному префиксу минус в 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) -
Преобразует число в строку, используя научную запись.
-
4. Константы
Константы в этом разделе актуальны только для модуля C. Они также включены в чистую версию Python для совместимости.
| 32-битный | 64-битный | |
|---|---|---|
| 425000000 | 999999999999999999 |
| 425000000 | 999999999999999999 |
| -425000000 | -999999999999999999 |
| -849999999 | -1999999999999999997 |
-
decimal.HAVE_THREADS -
Значение по умолчанию
True. Если Python скомпилирован без потоков, версия C автоматически отключает дорогостоящую механику контекста потоков. В этом случае значениеFalse.
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; в противном случае округление к нулю.
6. Сигналы
Сигналы представляют условия, возникающие во время вычислений. Каждый соответствует одному флагу контекста и одному разрешающему условию контекста.
Флаг контекста устанавливается всякий раз, когда возникает условие. После вычисления флаги могут быть проверены для получения информации (например, для определения того, было ли вычисление точным). После проверки флагов обязательно очистите все флаги перед началом следующего вычисления.
END_OF_DOCUMENT_MARKERЕсли у обработчика сигнала контекста включена ловушка, то условие вызывает исключение 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)
7. Примечания по числам с плавающей точкой
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')
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')
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. Рецепты
Вот несколько рецептов, которые служат вспомогательными функциями и демонстрируют способы работы с классом 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
10. Часто задаваемые вопросы о десятичных числах
В. Неудобно набирать 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.5/library/decimal.html