decimal — Десятичная фиксированная точка и плавающая точка арифметика
Исходный код: Lib/decimal.py
Модуль decimal предоставляет поддержку быстрой, корректно округлённой десятичной арифметики с плавающей точкой. Он предлагает несколько преимуществ перед типом данных float:
- Десятичная «арифметика основана на модели с плавающей точкой, разработанной с учётом человека, и имеет ключевой принцип — компьютеры должны предоставлять арифметику, которая работает так же, как и арифметика, которую люди изучают в школе». — выдержка из спецификации десятичной арифметики.
- Десятичные числа могут быть представлены точно. В отличие от чисел, таких как
1.1и2.2, в двоичной арифметике с плавающей точкой нет точного представления. Пользователи обычно не ожидают, что1.1 + 2.2будет отображаться как3.3000000000000003, как это происходит в двоичной арифметике с плавающей точкой. - Точность сохраняется и в арифметике. В десятичной арифметике с плавающей точкой
0.1 + 0.1 + 0.1 - 0.3точно равно нулю. В двоичной арифметике с плавающей точкой результат равен5.5511151231257827e-017. Хотя близко к нулю, различия препятствуют надёжной проверке на равенство, и различия могут накапливаться. По этой причине десятичная арифметика предпочтительна в приложениях бухгалтерского учёта, которые имеют жёсткие инварианты равенства. - Модуль decimal включает понятие значащих цифр, так что
1.30 + 1.20равно2.50. Завершающий ноль сохраняется для обозначения значащих цифр. Такое представление обычно используется в приложениях, работающих с деньгами. При умножении используется «школьный» подход, использующий все цифры множителей. Например,1.3 * 1.2даёт1.56, а1.30 * 1.20даёт1.5600. -
В отличие от двоичной арифметики с плавающей точкой на основе аппаратного обеспечения, модуль decimal имеет изменяемую пользователем точность (по умолчанию 28 знаков), которая может быть сколь угодно большой для данной задачи:
>>> from decimal import * >>> getcontext().prec = 6 >>> Decimal(1) / Decimal(7) Decimal('0.142857') >>> getcontext().prec = 28 >>> Decimal(1) / Decimal(7) Decimal('0.1428571428571428571428571429') - Как двоичная, так и десятичная арифметика с плавающей точкой реализованы на основе опубликованных стандартов. Хотя встроенный тип float раскрывает лишь небольшую часть своих возможностей, модуль decimal раскрывает все необходимые части стандарта. При необходимости программист имеет полный контроль над округлением и обработкой сигналов. Это включает возможность принудительного выполнения точной арифметики с использованием исключений для блокирования любых неточных операций.
- Модуль decimal был разработан для поддержки «без предубеждения как точной неокруглённой десятичной арифметики (иногда называемой арифметикой с фиксированной точкой), так и округлённой арифметики с плавающей точкой». — выдержка из спецификации десятичной арифметики.
Конструкция модуля основана на трёх понятиях: десятичное число, контекст арифметики и сигналы.
Десятичное число неизменяемо. Оно имеет знак, коэффициентные цифры и показатель степени. Для сохранения значащих цифр коэффициентные цифры не обрезают завершающие нули. Десятичные числа также включают специальные значения, такие как Infinity, -Infinity, и NaN. Стандарт также различает -0 и +0.
Контекст для арифметики — это среда, определяющая точность, правила округления, ограничения по показателям степени, флаги, указывающие результаты операций, и обработчики сигналов, которые определяют, рассматриваются ли сигналы как исключения. Варианты округления включают ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_UP и ROUND_05UP.
Сигналы — это группы исключительных условий, возникающих в ходе вычислений. В зависимости от потребностей приложения сигналы могут быть проигнорированы, рассмотрены как информационные или обработаны как исключения. Сигналы в модуле decimal: Clamped, InvalidOperation, DivisionByZero, Inexact, Rounded, Subnormal, Overflow, Underflow и FloatOperation.
Для каждого сигнала есть флаг и обработчик. Когда сигнал обнаруживается, его флаг устанавливается в единицу, а затем, если обработчик сигнала установлен в единицу, генерируется исключение. Флаги «липкие», поэтому пользователю необходимо сбросить их перед мониторингом вычислений.
См. также
- Спецификация IBM по общей десятичной арифметике, Спецификация общей десятичной арифметики.
Быстрый старт
Обычная начальная точка использования десятичных значений — импорт модуля, просмотр текущего контекста с помощью getcontext() и, при необходимости, установка новых значений точности, правил округления или разрешённых обработчиков:
>>> from decimal import *
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
InvalidOperation])
>>> getcontext().prec = 7 # Set a new precision
Экземпляры Decimal можно создавать из целых чисел, строк, чисел с плавающей точкой или кортежей. Создание из целого числа или числа с плавающей точкой выполняет точное преобразование значения этого целого числа или числа с плавающей точкой. Десятичные числа включают специальные значения, такие как NaN (значение «Не число»), положительные и отрицательные Infinity, и -0:
>>> getcontext().prec = 28
>>> Decimal(10)
Decimal('10')
>>> Decimal('3.14')
Decimal('3.14')
>>> Decimal(3.14)
Decimal('3.140000000000000124344978758017532527446746826171875')
>>> Decimal((0, (3, 1, 4), -2))
Decimal('3.14')
>>> Decimal(str(2.0 ** 0.5))
Decimal('1.4142135623730951')
>>> Decimal(2) ** Decimal('0.5')
Decimal('1.414213562373095048801688724')
>>> Decimal('NaN')
Decimal('NaN')
>>> Decimal('-Infinity')
Decimal('-Infinity')
Если сигнал FloatOperation отслеживается, случайное смешивание десятичных и чисел с плавающей точкой в конструкторах или операциях сравнения приводит к исключению:
>>> c = getcontext()
>>> c.traps[FloatOperation] = True
>>> Decimal(3.14)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') < 3.7
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') == 3.5
True
Добавлен в версии 3.3.
Значимость нового Decimal определяется исключительно количеством введённых цифр. Точность контекста и округление учитываются только при арифметических операциях.
>>> getcontext().prec = 6
>>> Decimal('3.0')
Decimal('3.0')
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988')
Если внутренние ограничения версии C превышены, создание десятичного числа приводит к InvalidOperation:
>>> Decimal("1e9999999999999999999")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
Изменено в версии 3.3.
Десятичные числа хорошо взаимодействуют со многими остальными частями Python. Вот небольшой десятичный пример с плавающей точкой:
>>> data = list(map(Decimal, '1.34 1.87 3.45 2.35 1.00 0.03 9.25'.split()))
>>> max(data)
Decimal('9.25')
>>> min(data)
Decimal('0.03')
>>> sorted(data)
[Decimal('0.03'), Decimal('1.00'), Decimal('1.34'), Decimal('1.87'),
Decimal('2.35'), Decimal('3.45'), Decimal('9.25')]
>>> sum(data)
Decimal('19.29')
>>> a,b,c = data[:3]
>>> str(a)
'1.34'
>>> float(a)
1.34
>>> round(a, 1)
Decimal('1.3')
>>> int(a)
1
>>> a * 5
Decimal('6.70')
>>> a * b
Decimal('2.5058')
>>> c % a
Decimal('0.77')
И некоторые математические функции также доступны для Decimal:
>>> getcontext().prec = 28
>>> Decimal(2).sqrt()
Decimal('1.414213562373095048801688724')
>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal('10').ln()
Decimal('2.302585092994045684017991455')
>>> Decimal('10').log10()
Decimal('1')
Метод quantize() округляет число до фиксированного показателя. Этот метод полезен для приложений, работающих с деньгами, которые часто округляют результаты до фиксированного числа знаков:
>>> Decimal('7.325').quantize(Decimal('.01'), rounding=ROUND_DOWN)
Decimal('7.32')
>>> Decimal('7.325').quantize(Decimal('1.'), rounding=ROUND_UP)
Decimal('8')
Как показано выше, функция getcontext() получает доступ к текущему контексту и позволяет изменять настройки. Этот подход удовлетворяет потребности большинства приложений.
Для более сложных задач может быть полезно создание альтернативных контекстов с помощью конструктора Context(). Чтобы сделать альтернативный контекст активным, используйте функцию setcontext().
В соответствии со стандартом, модуль decimal предоставляет два готовых стандартных контекста, BasicContext и ExtendedContext. Первый особенно полезен для отладки, так как многие обработчики включены:
>>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN)
>>> setcontext(myothercontext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857142857142857142857142857')
>>> ExtendedContext
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[], traps=[])
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857143')
>>> Decimal(42) / Decimal(0)
Decimal('Infinity')
>>> setcontext(BasicContext)
>>> Decimal(42) / Decimal(0)
Traceback (most recent call last):
File "<pyshell#143>", line 1, in -toplevel-
Decimal(42) / Decimal(0)
DivisionByZero: x / 0
Контексты также имеют флаги сигналов для мониторинга исключительных условий, возникающих при вычислениях. Флаги остаются установленными до явного сброса, поэтому лучше всего сбрасывать флаги перед каждой серией отслеживаемых вычислений, используя метод clear_flags().
>>> setcontext(ExtendedContext)
>>> getcontext().clear_flags()
>>> Decimal(355) / Decimal(113)
Decimal('3.14159292')
>>> getcontext()
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])
Запись flags показывает, что рациональное приближение к пи округлилось (цифры за пределами точности контекста были отброшены) и что результат неточен (некоторые из отброшенных цифр были ненулевыми).
Индивидуальные обработчики устанавливаются с помощью словаря в атрибуте traps контекста:
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(0)
Decimal('Infinity')
>>> getcontext().traps[DivisionByZero] = 1
>>> Decimal(1) / Decimal(0)
Traceback (most recent call last):
File "<pyshell#112>", line 1, in -toplevel-
Decimal(1) / Decimal(0)
DivisionByZero: x / 0
Большинство программ настраивают текущий контекст только один раз в начале программы. И во многих приложениях данные преобразуются в Decimal с помощью одного преобразования внутри цикла. После установки контекста и создания десятичных значений основная часть программы манипулирует данными так же, как и с другими числовыми типами Python.
Объекты Decimal
-
class decimal.Decimal(value='0', context=None) -
Создайте новый объект
Decimalна основе value.value может быть целым числом, строкой, кортежем,
floatили другим объектомDecimal. Если value не задано, возвращаетDecimal('0'). Если value является строкой, она должна соответствовать синтаксису десятичной числовой строки после удаления начальных и конечных пробелов, а также подчеркиваний во всем тексте:sign ::= '+' | '-' digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' indicator ::= 'e' | 'E' digits ::= digit [digit]... decimal-part ::= digits '.' [digits] | ['.'] digits exponent-part ::= indicator [sign] digits infinity ::= 'Infinity' | 'Inf' nan ::= 'NaN' [digits] | 'sNaN' [digits] numeric-value ::= decimal-part [exponent-part] | infinity numeric-string ::= [sign] numeric-value | [sign] nan
Также разрешены другие десятичные цифры Юникода, где
digitуказано выше. К ним относятся десятичные цифры из различных других алфавитов (например, арабские и деванагари цифры), а также полноширинные цифры'\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')Эта операция не зависит от контекста и выполняется без ошибок: флаги не изменяются, и округление не выполняется. В качестве исключения, версия на C может вызвать InvalidOperation, если второй операнд нельзя точно преобразовать.
-
exp(context=None) -
Возвращает значение функции (натурального) экспоненты
e**xв заданном числе. Результат корректно округляется с использованием режима округленияROUND_HALF_EVEN.>>> Decimal(1).exp() Decimal('2.718281828459045235360287471') >>> Decimal(321).exp() Decimal('2.561702493119680037517373933E+139')
-
classmethod from_float(f) -
Альтернативный конструктор, принимающий только экземпляры
floatилиint.Обратите внимание,
Decimal.from_float(0.1)не то же самое, чтоDecimal('0.1'). Поскольку 0,1 не может быть точно представлен в двоичной системе с плавающей запятой, значение хранится как ближайшее представимое значение, которое равно0x1.999999999999ap-4. Эквивалентное значение в десятичной системе равно0.1000000000000000055511151231257827021181583404541015625.Примечание
Начиная с Python 3.2, экземпляр
Decimalтакже может быть создан непосредственно изfloat.>>> Decimal.from_float(0.1) Decimal('0.1000000000000000055511151231257827021181583404541015625') >>> Decimal.from_float(float('nan')) Decimal('NaN') >>> Decimal.from_float(float('inf')) Decimal('Infinity') >>> Decimal.from_float(float('-inf')) Decimal('-Infinity')Добавлена в версии 3.1.
-
fma(other, third, context=None) -
Fused multiply-add. Возвращает 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) -
Используется для получения канонических значений класса эквивалентности в контексте текущей нити или заданном контексте.
Эта операция имеет такие же семантику, как у унарной операции плюс, за исключением того, что, если конечный результат является конечным, он приводится к самому простому виду с удалением всех конечных нулей и сохранением знака. То есть, пока коэффициент отличен от нуля и кратен десяти, коэффициент делится на десять, а показатель степени увеличивается на 1. В противном случае (коэффициент равен нулю) показатель степени устанавливается равным 0. Во всех случаях знак не изменяется.
Например,
Decimal('32.100')иDecimal('0.321000e+2')оба приводятся к эквивалентному значениюDecimal('32.1').Обратите внимание, что округление применяется до приведения к самому простому виду.
В последних версиях спецификации эта операция также известна как
reduce.
-
number_class(context=None) -
Возвращает строку, описывающую класс операнда. Возвращаемое значение является одной из следующих десяти строк.
-
"-Infinity", указывающее, что операнд равен отрицательной бесконечности. -
"-Normal", указывающее, что операнд является отрицательным нормальным числом. -
"-Subnormal", указывающее, что операнд отрицательный и субнормальный. -
"-Zero", указывающее, что операнд равен отрицательному нулю. -
"+Zero", указывающее, что операнд равен положительному нулю. -
"+Subnormal", указывающее, что операнд положительный и субнормальный. -
"+Normal", указывающее, что операнд является положительным нормальным числом. -
"+Infinity", указывающее, что операнд равен положительной бесконечности. -
"NaN", указывающее, что операнд является тихим NaN (Not a Number). -
"sNaN", указывающее, что операнд является сигнализирующим NaN.
-
-
quantize(exp, rounding=None, context=None) -
Возвращает значение, равное первому операнду после округления и с показателем степени второго операнда.
>>> Decimal('1.41421356').quantize(Decimal('1.000')) Decimal('1.414')В отличие от других операций, если длина коэффициента после операции quantize будет больше точности, то сигнализируется
InvalidOperation. Это гарантирует, что, если нет условия ошибки, показатель степени после операции quantize всегда равен показателю степени правого операнда.Также в отличие от других операций, quantize никогда не сигнализирует о переполнении, даже если результат является субнормальным и неточным.
Если показатель степени второго операнда больше, чем показатель степени первого, может потребоваться округление. В этом случае режим округления определяется аргументом
rounding, если он задан, иначе заданным аргументомcontext; если ни один из аргументов не задан, используется режим округления контекста текущей нити.Ошибка возвращается всякий раз, когда результирующий показатель степени больше
Emaxили меньшеEtiny().
-
radix() -
Возвращает
Decimal(10), основание (базу) системы счисления, в которой классDecimalвыполняет все арифметические операции. Включено для совместимости со спецификацией.
-
remainder_near(other, context=None) -
Возвращает остаток от деления self на other. Это отличается от
self % otherтем, что знак остатка выбирается таким образом, чтобы минимизировать его абсолютное значение. Более точно, возвращаемое значение равноself - n * other, гдеn- целое число, ближайшее к точному значениюself / other, и если два целых числа одинаково близки, то выбирается четное.Если результат равен нулю, то его знак будет равен знаку self.
>>> Decimal(18).remainder_near(Decimal(10)) Decimal('-2') >>> Decimal(25).remainder_near(Decimal(10)) Decimal('5') >>> Decimal(35).remainder_near(Decimal(10)) Decimal('-5')
-
rotate(other, context=None) -
Возвращает результат циклического сдвига цифр первого операнда на величину, заданную вторым операндом. Второй операнд должен быть целым числом в диапазоне от -точность до точности. Абсолютное значение второго операнда задает количество позиций для сдвига. Если второй операнд положителен, то сдвиг происходит влево; в противном случае сдвиг происходит вправо. Коэффициент первого операнда дополняется слева нулями до длины точность, если это необходимо. Знак и показатель степени первого операнда не изменяются.
-
same_quantum(other, context=None) -
Проверяет, имеют ли self и other одинаковый показатель степени или оба являются
NaN.Эта операция не зависит от контекста и является тихой: флаги не изменяются, и округление не выполняется. Как исключение, версия на C может вызвать InvalidOperation, если второй операнд не может быть преобразован точно.
-
scaleb(other, context=None) -
Возвращает первый операнд со скорректированным показателем степени вторым операндом. Эквивалентно, возвращает первый операнд, умноженный на
10**other. Второй операнд должен быть целым числом.
-
shift(other, context=None) -
Возвращает результат сдвига цифр первого операнда на величину, заданную вторым операндом. Второй операнд должен быть целым числом в диапазоне от -точность до точности. Абсолютное значение второго операнда задает количество позиций для сдвига. Если второй операнд положителен, то сдвиг происходит влево; в противном случае сдвиг происходит вправо. Цифры, смещенные в коэффициент, — нули. Знак и показатель степени первого операнда не изменяются.
-
sqrt(context=None) -
Возвращает квадратный корень аргумента с полной точностью.
-
to_eng_string(context=None) -
Преобразовать в строку, используя инженерную запись, если показатель степени необходим.
Инженерная запись имеет показатель степени, кратный 3. Это может оставить до 3 цифр слева от десятичной точки и может потребовать добавления одной или двух концевых нулей.
Например, это преобразует
Decimal('123E+1')вDecimal('1.23E+3').
-
to_integral(rounding=None, context=None) -
Идентично методу
to_integral_value(). Имяto_integralсохранено для совместимости со старыми версиями.
-
to_integral_exact(rounding=None, context=None) -
Округлить до ближайшего целого числа, сигнализируя
InexactилиRoundedпри необходимости. Режим округления определяется параметромrounding, если он задан, иначе заданнымcontext. Если ни один параметр не задан, используется режим округления текущего контекста.
-
to_integral_value(rounding=None, context=None) -
Округлить до ближайшего целого числа без сигнализации
InexactилиRounded. Если задан, применяет округление; в противном случае использует метод округления в предоставленном контексте или в текущем контексте.
Десятичные числа могут быть округлены с помощью функции
round():- round(number)
-
- round(number, ndigits)
-
Если ndigits не указано или
None, возвращает ближайшееintк number, привязывая к чётному значению при равенстве и игнорируя режим округления контекстаDecimal. ВызываетOverflowError, если number — бесконечность, илиValueError, если это NaN (тихий или сигнализирующий).Если ndigits —
int, режим округления контекста учитывается, и возвращаетсяDecimal, представляющий number, округлённый до ближайшего кратногоDecimal('1E-ndigits'); в этом случаеround(number, ndigits)эквивалентноself.quantize(Decimal('1E-ndigits')). ВозвращаетDecimal('NaN')если number — тихий NaN. ВызываетInvalidOperation, если number — бесконечность, сигнализирующий NaN, или если длина коэффициента после операции quantize превысит точность текущего контекста. Другими словами, для обычных случаев:- если ndigits положительно, возвращает number, округлённый до ndigits десятичных знаков;
- если ndigits равно нулю, возвращает number, округлённый до ближайшего целого;
- если ndigits отрицательно, возвращает number, округлённый до ближайшего кратного
10**abs(ndigits).
Например:
>>> from decimal import Decimal, getcontext, ROUND_DOWN >>> getcontext().rounding = ROUND_DOWN >>> round(Decimal('3.75')) # context rounding ignored 4 >>> round(Decimal('3.5')) # round-ties-to-even 4 >>> round(Decimal('3.75'), 0) # uses the context rounding Decimal('3') >>> round(Decimal('3.75'), 1) Decimal('3.7') >>> round(Decimal('3.75'), -1) Decimal('0E+1')
Логические операнды
Методы logical_and(), logical_invert(), logical_or() и logical_xor() ожидают в качестве аргументов логические операнды. Логический операнд — это экземпляр Decimal, у которого показатель степени и знак равны нулю, а все цифры — либо 0, либо 1.
Объекты контекста
Контексты — это среды для арифметических операций. Они управляют точностью, устанавливают правила округления, определяют, какие сигналы обрабатываются как исключения и ограничивают диапазон показателей степени.
В каждом потоке есть свой текущий контекст, к которому обращаются или который изменяют с помощью функций getcontext() и setcontext():
-
decimal.getcontext() -
Возвращает текущий контекст для активного потока.
-
decimal.setcontext(c) -
Устанавливает текущий контекст для активного потока на c.
Также можно использовать оператор with и функцию localcontext() для временного изменения активного контекста.
-
decimal.localcontext(ctx=None, **kwargs) -
Возвращает менеджер контекста, который устанавливает текущий контекст для активного потока в копию ctx при входе в оператор with и восстанавливает предыдущий контекст при выходе из оператора with. Если контекст не указан, используется копия текущего контекста. Аргумент kwargs используется для установки атрибутов нового контекста.
Например, следующий код устанавливает текущую точность десятичных знаков на 42 знака, выполняет вычисление и затем автоматически восстанавливает предыдущий контекст:
from decimal import localcontext with localcontext() as ctx: ctx.prec = 42 # Perform a high precision calculation s = calculate_something() s = +s # Round the final result back to the default precisionИспользование именованных аргументов:
from decimal import localcontext with localcontext(prec=42) as ctx: s = calculate_something() s = +sВызывает
TypeError, если kwargs предоставляет атрибут, которого не поддерживаетContext. Вызывает либоTypeError, либоValueError, если kwargs предоставляет недопустимое значение для атрибута.Изменено в версии 3.11:
localcontext()теперь поддерживает установку атрибутов контекста с помощью именованных аргументов.
Новые контексты также можно создавать с помощью конструктора Context, описанного ниже. Кроме того, модуль предоставляет три предопределённых контекста:
-
class decimal.BasicContext -
Это стандартный контекст, определённый в спецификации общей арифметики с десятичными числами. Точность установлена в девять знаков. Округление установлено в
ROUND_HALF_UP. Все флаги сброшены. Все ловушки включены (обрабатываются как исключения), за исключениемInexact,RoundedиSubnormal.Поскольку многие ловушки включены, этот контекст полезен для отладки.
-
class decimal.ExtendedContext -
Это стандартный контекст, определённый в спецификации общей арифметики с десятичными числами. Точность установлена в девять знаков. Округление установлено в
ROUND_HALF_EVEN. Все флаги сброшены. Никакие ловушки не включены (так что исключения не генерируются во время вычислений).Поскольку ловушки отключены, этот контекст полезен для приложений, которые предпочитают иметь значение результата
NaNилиInfinityвместо генерации исключений. Это позволяет приложению завершить выполнение при возникновении условий, которые иначе бы остановили программу.
-
class decimal.DefaultContext -
Этот контекст используется конструктором
Contextв качестве прототипа для новых контекстов. Изменение поля (например, точности) влияет на значение по умолчанию для новых контекстов, создаваемых конструкторомContext.Этот контекст наиболее полезен в многопоточных средах. Изменение поля до запуска потоков влияет на системные значения по умолчанию. Изменение полей после запуска потоков не рекомендуется, так как это потребует синхронизации потоков для предотвращения гонок.
В однопоточных средах предпочтительно вообще не использовать этот контекст. Вместо этого следует явно создавать контексты, как описано ниже.
Значения по умолчанию составляют
Context.prec=28,Context.rounding=ROUND_HALF_EVEN, и включенные ловушки дляOverflow,InvalidOperationиDivisionByZero.
Помимо трёх предоставленных контекстов, новые контексты можно создавать с помощью конструктора Context.
-
class decimal.Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)
-
Создаёт новый контекст. Если поле не указано или равно
None, значения по умолчанию копируются изDefaultContext. Если поле flags не указано или равноNone, все флаги сбрасываются.prec — целое число в диапазоне [
1,MAX_PREC], устанавливающее точность арифметических операций в контексте.Параметр rounding — одно из констант, перечисленных в разделе Режимы округления.
Поля 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) -
Применяет логическую операцию и между цифрами каждого операнда.
-
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.Decimal(0) ** Decimal(0)приводит кInvalidOperation, а еслиInvalidOperationне отлавливается, то приводит кDecimal('NaN').Изменено в версии 3.3: Модуль C вычисляет
power()в терминах правильно округленныхexp()иln()функций. Результат определён, но только «почти всегда правильно округленный».С тремя аргументами вычисляет
(x**y) % modulo. Для трех аргументов следующие ограничения на аргументы:- все три аргумента должны быть целыми
-
yдолжно быть неотрицательным - по крайней мере один из
xилиyдолжен быть ненулевым -
moduloдолжно быть ненулевым и содержать не более «precision» цифр
Значение, полученное от
Context.power(x, y, modulo), равно значению, которое было бы получено вычислением(x**y) % moduloс неограниченной точностью, но вычисляется более эффективно. Показатель степени результата равен нулю, независимо от показателей степениx,yиmodulo. Результат всегда точный.
-
quantize(x, y) -
Возвращает значение, равное x (округлённое), имеющее показатель степени y.
-
radix() -
Просто возвращает 10, поскольку это Decimal, :)
-
remainder(x, y) -
Возвращает остаток от целочисленного деления.
Знак результата, если он не нулевой, совпадает со знаком исходного делимого.
-
remainder_near(x, y) -
Возвращает
x - y * n, где n — целое число, ближайшее к точному значениюx / y(если результат 0, то его знак будет знаком x).
-
rotate(x, y) -
Возвращает повернутую копию x, y раз.
-
same_quantum(x, y) -
Возвращает
True, если два операнда имеют одинаковый показатель степени.
-
scaleb(x, y) -
Возвращает первый операнд после добавления ко второй величине её показателя.
-
shift(x, y) -
Возвращает сдвинутую копию x, y раз.
-
sqrt(x) -
Квадратный корень из неотрицательного числа с точностью контекста.
-
subtract(x, y) -
Возвращает разность между x и y.
-
to_eng_string(x) -
Преобразует в строку, используя инженерную нотацию, если нужен показатель степени.
Инженерная нотация имеет показатель степени, кратный 3. Это может оставить до 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 скомпилирован безconfigured using the --without-decimal-contextvar option, версия C использует локальную переменную потока, а не локальную переменную корутины, и значение равноFalse. Это немного быстрее в некоторых сценариях вложенных контекстов.Добавлен в версии 3.8.3.
Режимы округления
-
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; в противном случае округление к нулю.
Сигналы
Сигналы представляют условия, возникающие во время вычислений. Каждый соответствует одному флагу контекста и одному включателю ловушки контекста.
Флаг контекста устанавливается всякий раз, когда возникает условие. После вычисления флаги можно проверить для получения информации (например, чтобы определить, было ли вычисление точным). После проверки флагов обязательно очистите все флаги перед началом следующего вычисления.
Если включатель ловушки контекста установлен для сигнала, то условие вызывает повышение исключения Python. Например, если ловушка DivisionByZero установлена, то исключение DivisionByZero повышается при возникновении условия.
-
class decimal.Clamped -
Изменённый экспонент для соответствия ограничениям представления.
Обычно ограничение происходит, когда экспонент выходит за пределы
EminиEmaxконтекста. Если возможно, экспонент уменьшается для соответствия путём добавления нулей к коэффициенту.
-
class decimal.DecimalException -
Базовый класс для других сигналов и подкласс
ArithmeticError.
-
class decimal.DivisionByZero -
Сигнализирует деление конечного числа на ноль.
Может возникнуть при делении, модульном делении или возведении числа в отрицательную степень. Если этот сигнал не перехвачен, возвращает
Infinityили-Infinityсо знаком, определяемым входными данными вычисления.
-
class decimal.Inexact -
Указывает, что произошло округление, и результат не точный.
Сигнализирует, когда при округлении были отброшены ненулевые цифры. Возвращается округленный результат. Флаг сигнала или ловушка используются для обнаружения неточных результатов.
-
class decimal.InvalidOperation -
Было выполнено неверное действие.
Указывает, что была запрошена операция, которая не имеет смысла. Если не перехвачена, возвращает
NaN. Возможные причины:Infinity - Infinity 0 * Infinity Infinity / Infinity x % 0 Infinity % x sqrt(-x) and x > 0 0 ** 0 x ** (non-integer) x ** Infinity
-
class decimal.Overflow -
Переполнение.
Указывает, что экспонента больше, чем
Context.Emaxпосле округления. Если не перехвачена, результат зависит от режима округления, либо втягивается к наибольшему представимому конечному числу, либо округляется наружу доInfinity. В любом случае,InexactиRoundedтакже сигнализируются.
-
class decimal.Rounded -
Произошло округление, хотя, возможно, информация не была потеряна.
Сигнализируется всякий раз, когда округление отбрасывает цифры; даже если эти цифры равны нулю (например, округление
5.00до5.0). Если не перехвачена, возвращает результат без изменений. Этот сигнал используется для обнаружения потери значимых цифр.
-
class decimal.Subnormal -
Экспонента была ниже
Eminдо округления.Возникает, когда результат операции является субнормальным (экспонента слишком мала). Если не перехвачена, возвращает результат без изменений.
-
class decimal.Underflow -
Числовой подтекст с результатом, округленным до нуля.
Возникает, когда субнормальный результат округляется до нуля.
InexactиSubnormalтакже сигнализируются.
-
class decimal.FloatOperation -
Включение более строгих семантик для смешивания чисел с плавающей точкой и десятичных чисел.
Если сигнал не перехвачен (по умолчанию), смешивание чисел с плавающей точкой и десятичных чисел разрешено в конструкторе
Decimal,create_decimal()и всех операторах сравнения. Как преобразование, так и сравнение являются точными. Любое смешанное действие тихо регистрируется, устанавливаяFloatOperationв флагах контекста. Явные преобразования сfrom_float()илиcreate_decimal_from_float()не устанавливают флаг.В противном случае (сигнал перехвачен), только сравнения на равенство и явные преобразования безмолвно обрабатываются. Все другие смешанные операции вызывают
FloatOperation.
В следующей таблице обобщается иерархия сигналов:
exceptions.ArithmeticError(exceptions.Exception)
DecimalException
Clamped
DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
Inexact
Overflow(Inexact, Rounded)
Underflow(Inexact, Rounded, Subnormal)
InvalidOperation
Rounded
Subnormal
FloatOperation(DecimalException, exceptions.TypeError)
Примечания по работе с плавающей точкой
Устранение ошибки округления с помощью увеличения точности
Использование десятичных чисел с плавающей точкой устраняет ошибки представления десятичных дробей (позволяя точно представлять 0.1); однако некоторые операции все равно могут привести к ошибке округления, когда количество знаков после запятой превышает заданную точность.
Влияние ошибки округления может усиливаться при сложении или вычитании почти взаимно компенсирующих величин, что приводит к потере значимости. Кнут приводит два наглядных примера, где округленное вычисление с плавающей точкой с недостаточной точностью приводит к нарушению ассоциативного и дистрибутивного свойств сложения:
# Examples from Seminumerical Algorithms, Section 4.2.2.
>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 8
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.5111111')
>>> u + (v + w)
Decimal('10')
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.01')
>>> u * (v+w)
Decimal('0.0060000')
Модуль decimal позволяет восстановить тождества, увеличив точность настолько, чтобы избежать потери значимости:
>>> getcontext().prec = 20
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.51111111')
>>> u + (v + w)
Decimal('9.51111111')
>>>
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.0060000')
>>> u * (v+w)
Decimal('0.0060000')
Специальные значения
Система чисел для модуля decimal содержит специальные значения, включая NaN, sNaN, -Infinity, Infinity, а также два нуля, +0 и -0.
Бесконечности могут быть построены непосредственно с помощью: Decimal('Infinity'). Также они могут возникнуть при делении на ноль, если сигнал DivisionByZero не перехвачен. Аналогично, при отсутствии перехвата сигнала Overflow может получиться бесконечность в результате округления за пределы границ наибольшего представимого числа.
Бесконечности имеют знак (аффинные) и могут использоваться в арифметических операциях, где они рассматриваются как очень большие, неопределенные числа. Например, добавление константы к бесконечности даёт другой бесконечный результат.
Некоторые операции неопределены и возвращают NaN, или, если сигнал InvalidOperation перехвачен, вызывают исключение. Например, 0/0 возвращает NaN, что означает «не число». Этот вид NaN является тихим и, будучи созданным, будет передаваться через другие вычисления, всегда приводя к другому NaN. Это поведение может быть полезно для серии вычислений, в которых иногда отсутствуют входные данные — оно позволяет вычислению продолжаться, одновременно помечая определённые результаты как недействительные.
Вариацией является sNaN — оно сигнализирует, а не остаётся тихим после каждой операции. Это полезное возвращаемое значение, когда недействительный результат должен прервать вычисление для специальной обработки.
Поведение операторов сравнения Python может быть немного неожиданным, когда задействовано NaN. Тест на равенство, где один из операндов — тихий или сигнализирующий NaN — всегда возвращает False (даже при Decimal('NaN')==Decimal('NaN')), а тест на неравенство всегда возвращает True. Попытка сравнить два десятичных числа с помощью любого из операторов <, <=, > или >= вызовет сигнал InvalidOperation, если один из операндов — NaN, и вернёт False, если этот сигнал не перехвачен. Обратите внимание, что спецификация общей десятичной арифметики не определяет поведение прямых сравнений; эти правила для сравнений, включающих NaN, взяты из стандарта IEEE 854 (см. таблицу 3 в разделе 5.7). Чтобы обеспечить строгое соответствие стандарту, используйте методы compare() и compare_signal() вместо этого.
Отрицательные нули могут возникнуть в результате вычислений, которые переполняются. Они сохраняют знак, который получился бы, если бы вычисление было выполнено с большей точностью. Поскольку их величина равна нулю, как положительный, так и отрицательный нули обрабатываются как равные, а их знак является информативным.
В дополнение к двум отрицательным нулям, которые различны, но равны, существуют различные представления нуля с разной точностью, но эквивалентные по значению. Это требует некоторой привычки. Для глаза, привыкшего к нормализованным представлениям с плавающей точкой, не сразу понятно, что следующее вычисление возвращает значение, равное нулю:
>>> 1 / Decimal('Infinity')
Decimal('0E-1000026')
Работа с потоками
Функция getcontext() получает другой объект Context для каждого потока. Наличие отдельных контекстов потоков означает, что потоки могут вносить изменения (такие как getcontext().prec=10) без вмешательства в работу других потоков.
Аналогично, функция setcontext() автоматически присваивает свой целевой объект текущему потоку.
Если функция setcontext() не вызывалась до getcontext(), то getcontext() автоматически создаст новый контекст для использования в текущем потоке.
Новый контекст копируется из прототипного контекста под названием DefaultContext. Чтобы управлять значениями по умолчанию, чтобы каждый поток использовал одни и те же значения во всём приложении, напрямую модифицируйте объект DefaultContext. Это необходимо сделать до запуска потоков, чтобы не возникло состояния гонки между потоками, вызывающими getcontext(). Например:
# Set applicationwide defaults for all threads about to be launched DefaultContext.prec = 12 DefaultContext.rounding = ROUND_DOWN DefaultContext.traps = ExtendedContext.traps.copy() DefaultContext.traps[InvalidOperation] = 1 setcontext(DefaultContext) # Afterwards, the threads can be started t1.start() t2.start() t3.start() . . .
Рецепты
Вот несколько рецептов, которые служат вспомогательными функциями и демонстрируют способы работы с классом Decimal:
def moneyfmt(value, places=2, curr='', sep=',', dp='.',
pos='', neg='-', trailneg=''):
"""Convert Decimal to a money formatted string.
places: required number of places after the decimal point
curr: optional currency symbol before the sign (may be blank)
sep: optional grouping separator (comma, period, space, or blank)
dp: decimal point indicator (comma or period)
only specify as blank when places is zero
pos: optional sign for positive numbers: '+', space or blank
neg: optional sign for negative numbers: '-', '(', space or blank
trailneg:optional trailing minus indicator: '-', ')', space or blank
>>> d = Decimal('-1234567.8901')
>>> moneyfmt(d, curr='$')
'-$1,234,567.89'
>>> moneyfmt(d, places=0, sep='.', dp='', neg='', trailneg='-')
'1.234.568-'
>>> moneyfmt(d, curr='$', neg='(', trailneg=')')
'($1,234,567.89)'
>>> moneyfmt(Decimal(123456789), sep=' ')
'123 456 789.00'
>>> moneyfmt(Decimal('-0.02'), neg='<', trailneg='>')
'<0.02>'
"""
q = Decimal(10) ** -places # 2 places --> '0.01'
sign, digits, exp = value.quantize(q).as_tuple()
result = []
digits = list(map(str, digits))
build, next = result.append, digits.pop
if sign:
build(trailneg)
for i in range(places):
build(next() if digits else '0')
if places:
build(dp)
if not digits:
build('0')
i = 0
while digits:
build(next())
i += 1
if i == 3 and digits:
i = 0
build(sep)
build(curr)
build(neg if sign else pos)
return ''.join(reversed(result))
def pi():
"""Compute Pi to the current precision.
>>> print(pi())
3.141592653589793238462643383
"""
getcontext().prec += 2 # extra digits for intermediate steps
three = Decimal(3) # substitute "three=3.0" for regular floats
lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
while s != lasts:
lasts = s
n, na = n+na, na+8
d, da = d+da, da+32
t = (t * n) / d
s += t
getcontext().prec -= 2
return +s # unary plus applies the new precision
def exp(x):
"""Return e raised to the power of x. Result type matches input type.
>>> print(exp(Decimal(1)))
2.718281828459045235360287471
>>> print(exp(Decimal(2)))
7.389056098930650227230427461
>>> print(exp(2.0))
7.38905609893
>>> print(exp(2+0j))
(7.38905609893+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num = 0, 0, 1, 1, 1
while s != lasts:
lasts = s
i += 1
fact *= i
num *= x
s += num / fact
getcontext().prec -= 2
return +s
def cos(x):
"""Return the cosine of x as measured in radians.
The Taylor series approximation works best for a small value of x.
For larger values, first compute x = x % (2 * pi).
>>> print(cos(Decimal('0.5')))
0.8775825618903727161162815826
>>> print(cos(0.5))
0.87758256189
>>> print(cos(0.5+0j))
(0.87758256189+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num, sign = 0, 0, 1, 1, 1, 1
while s != lasts:
lasts = s
i += 2
fact *= i * (i-1)
num *= x * x
sign *= -1
s += num / fact * sign
getcontext().prec -= 2
return +s
def sin(x):
"""Return the sine of x as measured in radians.
The Taylor series approximation works best for a small value of x.
For larger values, first compute x = x % (2 * pi).
>>> print(sin(Decimal('0.5')))
0.4794255386042030002732879352
>>> print(sin(0.5))
0.479425538604
>>> print(sin(0.5+0j))
(0.479425538604+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1
while s != lasts:
lasts = s
i += 2
fact *= i * (i-1)
num *= x * x
sign *= -1
s += num / fact * sign
getcontext().prec -= 2
return +s
Часто задаваемые вопросы по Decimal
В. Ввод decimal.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')]
В. Когда происходит округление в вычислении?
О. Оно происходит после вычисления. Философия спецификации decimal заключается в том, что числа считаются точными и создаются независимо от текущего контекста. Они могут даже иметь большую точность, чем текущий контекст. Вычисления обрабатываются с этими точными входными данными, а затем округление (или другие операции контекста) применяется к результату вычисления:
>>> getcontext().prec = 5
>>> pi = Decimal('3.1415926535') # More than 5 digits
>>> pi # All digits are retained
Decimal('3.1415926535')
>>> pi + 0 # Rounded after an addition
Decimal('3.1416')
>>> pi - Decimal('0.00005') # Subtract unrounded numbers, then round
Decimal('3.1415')
>>> pi + 0 - Decimal('0.00005'). # Intermediate values are rounded
Decimal('3.1416')
В. Некоторые десятичные значения всегда выводятся в экспоненциальной форме. Есть ли способ получить неэкспоненциальное представление?
О. Для некоторых значений экспоненциальная форма является единственным способом выражения числа значащих цифр в коэффиценте. Например, представление 5.0E+3 как 5000 сохраняет значение постоянным, но не может показать исходную точность в два знака после запятой.
Если приложение не заботится о слежении за точностью, то легко убрать экспоненту и концевые нули, потеряв точность, но сохранив значение неизменным:
>>> def remove_exponent(d): ... return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')
В. Есть ли способ преобразовать обычное число с плавающей точкой в Decimal?
О. Да, любое двоичное число с плавающей точкой может быть точно выражено как Decimal, хотя точное преобразование может потребовать большей точности, чем подсказывает интуиция:
>>> Decimal(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875')
В. Как в сложном вычислении убедиться, что не получен ложный результат из-за недостаточной точности или аномалий округления?
О. Модуль decimal упрощает проверку результатов. Лучшей практикой является повторное выполнение вычислений с большей точностью и различными режимами округления. Существенно отличающиеся результаты указывают на недостаточную точность, проблемы с режимом округления, плохо обусловленные входные данные или численный нестабильный алгоритм.
В. Я заметил, что точность контекста применяется к результатам операций, но не к входным данным. На что следует обратить внимание при смешивании значений с разной точностью?
О. Да. Принцип заключается в том, что все значения считаются точными, как и арифметика над этими значениями. Округление применяется только к результатам. Преимущество для входных данных заключается в том, что «ввод - это то, что вы получаете». Недостатком является то, что результаты могут выглядеть странно, если вы забудете, что входные данные не были округлены:
>>> getcontext().prec = 3
>>> Decimal('3.104') + Decimal('2.104')
Decimal('5.21')
>>> Decimal('3.104') + Decimal('0.000') + Decimal('2.104')
Decimal('5.20')
Решение заключается в увеличении точности или принудительном округлении входных данных с помощью унарной операции плюс:
>>> getcontext().prec = 3
>>> +Decimal('1.23456789') # unary plus triggers rounding
Decimal('1.23')
В качестве альтернативы входные данные можно округлить при создании, используя метод Context.create_decimal():
>>> Context(prec=5, rounding=ROUND_DOWN).create_decimal('1.2345678')
Decimal('1.2345')
В. Быстро ли реализация CPython для больших чисел?
О. Да. В реализациях CPython и PyPy3 версии модуля decimal на C/CFFI интегрируют высокопроизводительную библиотеку libmpdec для произвольной точности с корректным округлением арифметики десятичных чисел с плавающей точкой [1]. libmpdec использует умножение Карацубы для средних чисел и преобразование по теории чисел для очень больших чисел.
Контекст должен быть адаптирован для точной арифметики с произвольной точностью. Emin и Emax всегда должны быть установлены на максимальные значения, clamp всегда должно быть 0 (по умолчанию). Установка prec требует определенной осторожности.
Самый простой подход для работы с арифметикой больших чисел заключается в использовании максимального значения для prec [2]:
>>> setcontext(Context(prec=MAX_PREC, Emax=MAX_EMAX, Emin=MIN_EMIN))
>>> x = Decimal(2) ** 256
>>> x / 128
Decimal('904625697166532776746648320380374280103671755200316906558262375061821325312')
Для результатов с неточностью MAX_PREC слишком велико на 64-битных платформах, и доступной памяти будет недостаточно:
>>> Decimal(1) / 3 Traceback (most recent call last): File "<stdin>", line 1, in <module> MemoryError
В системах с перераспределением памяти (например, Linux) более сложный подход заключается в настройке prec в соответствии с доступной оперативной памятью. Предположим, у вас 8 ГБ ОЗУ и ожидается 10 одновременных операндов, каждый из которых использует максимум 500 МБ:
>>> import sys >>> >>> # Maximum number of digits for a single operand using 500MB in 8-byte words >>> # with 19 digits per word (4-byte and 9 digits for the 32-bit build): >>> maxdigits = 19 * ((500 * 1024**2) // 8) >>> >>> # Check that this works: >>> c = Context(prec=maxdigits, Emax=MAX_EMAX, Emin=MIN_EMIN) >>> c.traps[Inexact] = True >>> setcontext(c) >>> >>> # Fill the available precision with nines: >>> x = Decimal(0).logical_invert() * 9 >>> sys.getsizeof(x) 524288112 >>> x + 2 Traceback (most recent call last): File "<stdin>", line 1, in <module> decimal.Inexact: [<class 'decimal.Inexact'>]
В общем случае (особенно в системах без перераспределения памяти) рекомендуется устанавливать еще более ограниченные границы и устанавливать флаг Inexact, если все вычисления ожидаются точными.
© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/library/decimal.html