decimal
— Десятичная арифметика с фиксированной и плавающей запятой¶
Исходный код: Lib/decimal.py
Модуль decimal
обеспечивает поддержку быстрого и корректного округления десятичных чисел с плавающей запятой. Он обладает рядом преимуществ по сравнению с типом данных float
:
Decimal » основана на модели с плавающей запятой, которая была разработана с учетом потребностей людей и обязательно имеет основополагающий руководящий принцип - компьютеры должны обеспечивать арифметику, которая работает так же, как арифметика, которую люди изучают в школе». - выдержка из спецификации десятичной арифметики.
Десятичные числа могут быть представлены в точности. Напротив, такие числа, как
1.1
и2.2
, не имеют точных представлений в двоичном формате с плавающей запятой. Конечные пользователи обычно не ожидают, что1.1 + 2.2
будет отображаться как3.3000000000000003
, как это происходит с двоичной точкой с плавающей запятой.Точность переносится на арифметику. В десятичной системе счисления с плавающей запятой
0.1 + 0.1 + 0.1 - 0.3
в точности равно нулю. В двоичной системе счисления с плавающей запятой результат равен5.5511151231257827e-017
. При приближении к нулю различия препятствуют надежной проверке на равенство и могут накапливаться. По этой причине десятичная дробь предпочтительнее в бухгалтерских приложениях, которые имеют строгие инварианты равенства.Десятичный модуль включает в себя представление о значащих позициях, так что
1.30 + 1.20
равно2.50
. Конечный ноль сохраняется для указания значимости. Это обычное представление для приложений, работающих с денежными средствами. Для умножения в «школьном учебнике» используются все цифры, входящие в состав множимых. Например,1.3 * 1.2
дает1.56
, а1.30 * 1.20
-1.5600
.В отличие от аппаратного двоичного модуля с плавающей запятой, десятичный модуль имеет изменяемую пользователем точность (по умолчанию 28 знаков), которая может быть настолько большой, насколько это необходимо для данной задачи:
>>> from decimal import * >>> getcontext().prec = 6 >>> Decimal(1) / Decimal(7) Decimal('0.142857') >>> getcontext().prec = 28 >>> Decimal(1) / Decimal(7) Decimal('0.1428571428571428571428571429')
Как двоичная, так и десятичная система с плавающей запятой реализованы в соответствии с опубликованными стандартами. В то время как встроенный модуль с плавающей запятой предоставляет лишь небольшую часть своих возможностей, десятичный модуль предоставляет все необходимые части стандарта. При необходимости программист имеет полный контроль над округлением и обработкой сигналов. Это включает в себя возможность применения точной арифметики с помощью исключений для блокировки любых неточных операций.
Модуль decimal был разработан для поддержки «без каких-либо предубеждений как точной неокругленной десятичной арифметики (иногда называемой арифметикой с фиксированной запятой), так и округленной арифметики с плавающей запятой». – выдержка из спецификации десятичной арифметики.
Дизайн модуля основан на трех понятиях: десятичное число, контекст для арифметики и сигналы.
Десятичное число является неизменяемым. У него есть знак, цифры коэффициента и показатель степени. Чтобы сохранить значимость, цифры коэффициента не усекают конечные нули. Десятичные дроби также содержат специальные значения, такие как Infinity
, -Infinity
, и NaN
. Стандарт также отличает -0
от +0
.
Контекст для арифметики - это среда, определяющая точность, правила округления, ограничения на экспоненты, флаги, указывающие на результаты операций, и средства перехвата, которые определяют, будут ли сигналы рассматриваться как исключения. Параметры округления включают в себя ROUND_CEILING
, ROUND_DOWN
, ROUND_FLOOR
, ROUND_HALF_DOWN
, ROUND_HALF_EVEN
, ROUND_HALF_UP
, ROUND_UP
, и ROUND_05UP
.
Сигналы - это группы исключительных условий, возникающих в ходе вычислений. В зависимости от потребностей приложения сигналы могут игнорироваться, рассматриваться как информационные или рассматриваться как исключения. Сигналами в десятичном модуле являются: Clamped
, InvalidOperation
, DivisionByZero
, Inexact
, Rounded
, Subnormal
, Overflow
, Underflow
и FloatOperation
.
Для каждого сигнала есть флаг и функция перехвата. При обнаружении сигнала его флаг устанавливается равным единице, затем, если функция перехвата установлена равной единице, генерируется исключение. Флажки являются фиксированными, поэтому пользователю необходимо сбросить их, прежде чем отслеживать вычисления.
См.также
Общая спецификация десятичной арифметики IBM, The General Decimal Arithmetic Specification.
Краткое руководство по началу работы¶
Обычно использование десятичных дробей начинается с импорта модуля, просмотра текущего контекста с помощью getcontext()
и, при необходимости, установки новых значений для точности, округления или включенных ловушек:
>>> from decimal import *
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
InvalidOperation])
>>> getcontext().prec = 7 # Set a new precision
Десятичные экземпляры могут быть созданы из целых чисел, строк, чисел с плавающей точкой или кортежей. Построение из целого числа или числа с плавающей точкой выполняет точное преобразование значения этого целого числа или числа с плавающей точкой. Десятичные числа включают в себя специальные значения, такие как NaN
, что означает «Не число», положительные и отрицательные Infinity
и -0
:
>>> getcontext().prec = 28
>>> Decimal(10)
Decimal('10')
>>> Decimal('3.14')
Decimal('3.14')
>>> Decimal(3.14)
Decimal('3.140000000000000124344978758017532527446746826171875')
>>> Decimal((0, (3, 1, 4), -2))
Decimal('3.14')
>>> Decimal(str(2.0 ** 0.5))
Decimal('1.4142135623730951')
>>> Decimal(2) ** Decimal('0.5')
Decimal('1.414213562373095048801688724')
>>> Decimal('NaN')
Decimal('NaN')
>>> Decimal('-Infinity')
Decimal('-Infinity')
Если сигнал FloatOperation
перехвачен, случайное смешивание десятичных и плавающих чисел в конструкторах или упорядочивание сравнений приводит к возникновению исключения:
>>> c = getcontext()
>>> c.traps[FloatOperation] = True
>>> Decimal(3.14)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') < 3.7
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') == 3.5
True
Добавлено в версии 3.3.
Значение нового десятичного числа определяется исключительно количеством введенных цифр. Точность контекста и округление имеют значение только при выполнении арифметических операций.
>>> getcontext().prec = 6
>>> Decimal('3.0')
Decimal('3.0')
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988')
Если превышены внутренние ограничения версии C, то при построении десятичного числа возникает InvalidOperation
:
>>> Decimal("1e9999999999999999999")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
Изменено в версии 3.3.
Десятичные дроби хорошо взаимодействуют со многими другими элементами Python. Вот небольшой демонстрационный пример десятичной системы счисления с плавающей запятой:
>>> data = list(map(Decimal, '1.34 1.87 3.45 2.35 1.00 0.03 9.25'.split()))
>>> max(data)
Decimal('9.25')
>>> min(data)
Decimal('0.03')
>>> sorted(data)
[Decimal('0.03'), Decimal('1.00'), Decimal('1.34'), Decimal('1.87'),
Decimal('2.35'), Decimal('3.45'), Decimal('9.25')]
>>> sum(data)
Decimal('19.29')
>>> a,b,c = data[:3]
>>> str(a)
'1.34'
>>> float(a)
1.34
>>> round(a, 1)
Decimal('1.3')
>>> int(a)
1
>>> a * 5
Decimal('6.70')
>>> a * b
Decimal('2.5058')
>>> c % a
Decimal('0.77')
И некоторые математические функции также доступны для десятичной системы счисления.:
>>> getcontext().prec = 28
>>> Decimal(2).sqrt()
Decimal('1.414213562373095048801688724')
>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal('10').ln()
Decimal('2.302585092994045684017991455')
>>> Decimal('10').log10()
Decimal('1')
Метод quantize()
округляет число до фиксированного показателя. Этот метод полезен для финансовых приложений, которые часто округляют результаты до фиксированного числа пунктов:
>>> Decimal('7.325').quantize(Decimal('.01'), rounding=ROUND_DOWN)
Decimal('7.32')
>>> Decimal('7.325').quantize(Decimal('1.'), rounding=ROUND_UP)
Decimal('8')
Как показано выше, функция getcontext()
обращается к текущему контексту и позволяет изменять настройки. Этот подход отвечает потребностям большинства приложений.
Для более сложной работы может оказаться полезным создать альтернативные контексты с помощью конструктора Context(). Чтобы активировать альтернативный контекст, используйте функцию setcontext()
.
В соответствии со стандартом, модуль decimal
предоставляет два готовых к использованию стандартных контекста, BasicContext
и ExtendedContext
. Первый особенно полезен для отладки, поскольку многие ловушки включены:
>>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN)
>>> setcontext(myothercontext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857142857142857142857142857')
>>> ExtendedContext
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[], traps=[])
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857143')
>>> Decimal(42) / Decimal(0)
Decimal('Infinity')
>>> setcontext(BasicContext)
>>> Decimal(42) / Decimal(0)
Traceback (most recent call last):
File "<pyshell#143>", line 1, in -toplevel-
Decimal(42) / Decimal(0)
DivisionByZero: x / 0
Контексты также содержат сигнальные флажки для отслеживания исключительных условий, возникающих во время вычислений. Флажки остаются установленными до тех пор, пока они явно не будут сброшены, поэтому лучше всего снимать флажки перед каждым набором отслеживаемых вычислений, используя метод clear_flags()
.
>>> setcontext(ExtendedContext)
>>> getcontext().clear_flags()
>>> Decimal(355) / Decimal(113)
Decimal('3.14159292')
>>> getcontext()
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])
Запись flags показывает, что рациональное приближение к pi было округлено (цифры, превышающие точность контекста, были отброшены) и что результат неточен (некоторые из отброшенных цифр были отличны от нуля).
Отдельные ловушки устанавливаются с помощью словаря в атрибуте traps
контекста:
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(0)
Decimal('Infinity')
>>> getcontext().traps[DivisionByZero] = 1
>>> Decimal(1) / Decimal(0)
Traceback (most recent call last):
File "<pyshell#112>", line 1, in -toplevel-
Decimal(1) / Decimal(0)
DivisionByZero: x / 0
Большинство программ корректируют текущий контекст только один раз, в начале работы программы. И во многих приложениях данные преобразуются в Decimal
с помощью однократного приведения в цикле. С заданным контекстом и созданными десятичными числами основная часть программы обрабатывает данные не иначе, чем с другими числовыми типами Python.
Десятичные объекты¶
- class decimal.Decimal(value='0', context=None)¶
Создайте новый объект
Decimal
на основе значения *.значением может быть целое число, строка, кортеж,
float
или другой объектDecimal
. Если значение не задано, возвращаетDecimal('0')
. Если value является строкой, то она должна соответствовать синтаксису десятичной числовой строки после удаления начальных и конечных пробелов, а также подчеркиваний по всему тексту:sign ::= '+' | '-' digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' indicator ::= 'e' | 'E' digits ::= digit [digit]... decimal-part ::= digits '.' [digits] | ['.'] digits exponent-part ::= indicator [sign] digits infinity ::= 'Infinity' | 'Inf' nan ::= 'NaN' [digits] | 'sNaN' [digits] numeric-value ::= decimal-part [exponent-part] | infinity numeric-string ::= [sign] numeric-value | [sign] nan
Другие десятичные разряды Юникода также разрешены там, где
digit
указано выше. К ним относятся десятичные цифры из различных других алфавитов (например, арабо-индийские цифры и цифры Деванагари), а также цифры полной ширины от'\uff10'
до'\uff19'
.Если значение равно
tuple
, оно должно состоять из трех компонентов: знака (0
для положительного значения или1
для отрицательного),tuple
цифр и целого показателя степени. Например,Decimal((0, (1, 4, 1, 4), -3))
возвращаетDecimal('1.414')
.Если значение равно
float
, двоичное значение с плавающей запятой преобразуется без потерь в его точный десятичный эквивалент. Для этого преобразования часто требуется точность в 53 или более разряда. Например,Decimal(float('1.1'))
преобразуется вDecimal('1.100000000000000088817841970012523233890533447265625')
.Точность контекста не влияет на количество сохраняемых цифр. Это определяется исключительно количеством цифр в value. Например,
Decimal('3.00000')
записывает все пять нулей, даже если точность контекста составляет всего три.Назначение аргумента context - определить, что делать, если value является неправильно сформированной строкой. Если контекст перехватывает
InvalidOperation
, возникает исключение; в противном случае конструктор возвращает новое десятичное значение со значениемNaN
.После создания объекты
Decimal
являются неизменяемыми.Изменено в версии 3.2: Аргументом конструктора теперь может быть экземпляр
float
.Изменено в версии 3.3: аргументы
float
вызывают исключение, если установлен параметрFloatOperation
. По умолчанию параметр отключен.Изменено в версии 3.6: Для группировки разрешены символы подчеркивания, как в случае с целыми числами и литералами с плавающей запятой в коде.
Десятичные объекты с плавающей запятой имеют много общих свойств с другими встроенными числовыми типами, такими как
float
иint
. Применяются все обычные математические операции и специальные методы. Аналогично, десятичные объекты можно копировать, выбирать, печатать, использовать в качестве ключей словаря, элементов набора, сравнивать, сортировать и приводить к другому типу (например,float
илиint
).Существуют некоторые небольшие различия между арифметикой с десятичными объектами и арифметикой с целыми числами и числами с плавающей точкой. Когда оператор остатка
%
применяется к десятичным объектам, знаком результата является знак делимого, а не знак делителя:>>> (-7) % 4 1 >>> Decimal(-7) % Decimal(4) Decimal('-3')
Оператор целочисленного деления
//
ведет себя аналогично, возвращая целую часть истинного частного (с уменьшением до нуля), а не его значение, чтобы сохранить обычное тождествоx == (x // y) * y + x % y
:>>> -7 // 4 -2 >>> Decimal(-7) // Decimal(4) Decimal('-1')
Операторы
%
и//
реализуют операцииremainder
иdivide-integer
(соответственно), как описано в спецификации.Десятичные объекты, как правило, нельзя комбинировать с числами с плавающей запятой или экземплярами
fractions.Fraction
в арифметических операциях: попытка добавитьDecimal
кfloat
, например, приведет к появлениюTypeError
. Однако можно использовать операторы сравнения в Python для сравнения экземпляраDecimal
x
с другим числомy
. Это позволяет избежать путаницы в результатах при сравнении чисел разных типов на равенство.Изменено в версии 3.2: Теперь полностью поддерживаются сравнения смешанных типов между экземплярами
Decimal
и другими числовыми типами.В дополнение к стандартным числовым свойствам, десятичные объекты с плавающей запятой также имеют ряд специализированных методов:
- adjusted()¶
Возвращает скорректированный показатель степени после смещения крайних правых цифр коэффициентов до тех пор, пока не останется только начальная цифра:
Decimal('321e+5').adjusted()
возвращает семь. Используется для определения положения старшей цифры по отношению к десятичной запятой.
- as_integer_ratio()¶
Возвращает пару
(n, d)
целых чисел, которые представляют данный экземплярDecimal
в виде дроби, с наименьшим значением и положительным знаменателем:>>> Decimal('-3.14').as_integer_ratio() (-157, 50)
Преобразование выполнено точно. Повысьте значение OverflowError для бесконечностей и ValueError для NANS.
Добавлено в версии 3.6.
- as_tuple()¶
Возвращает named tuple представление числа:
DecimalTuple(sign, digits, exponent)
.
- canonical()¶
Возвращает каноническую кодировку аргумента. В настоящее время кодировка экземпляра
Decimal
всегда является канонической, поэтому эта операция возвращает его аргумент без изменений.
- compare(other, context=None)¶
Сравните значения двух десятичных экземпляров.
compare()
возвращает десятичный экземпляр, и если любой из операндов является NaN, то результатом будет NaN:a or b is a NaN ==> Decimal('NaN') a < b ==> Decimal('-1') a == b ==> Decimal('0') a > b ==> Decimal('1')
- compare_signal(other, context=None)¶
Эта операция идентична методу
compare()
, за исключением того, что все NAN сигнализируют. То есть, если ни один из операндов не является сигнальным NaN, то любой тихий NaN-операнд обрабатывается как сигнальный NaN.
- compare_total(other, context=None)¶
Сравните два операнда, используя их абстрактное представление, а не числовое значение. Аналогично методу
compare()
, но в результате получается общий порядок дляDecimal
экземпляров. Два экземпляраDecimal
с одинаковым числовым значением, но разными представлениями сравниваются неравномерно в этом порядке:>>> Decimal('12.0').compare_total(Decimal('12')) Decimal('-1')
Бесшумные и сигнализирующие NAN также включены в общий заказ. Результатом выполнения этой функции является
Decimal('0')
, если оба операнда имеют одинаковое представление,Decimal('-1')
, если первый операнд в общем порядке ниже второго, иDecimal('1')
, если первый операнд в общем порядке выше чем второй операнд. Подробную информацию об общем объеме заказа смотрите в спецификации.Эта операция не зависит от контекста и выполняется без проблем: никакие флаги не меняются и округление не выполняется. В качестве исключения версия C может вызвать недействительную операцию, если второй операнд не может быть преобразован точно.
- compare_total_mag(other, context=None)¶
Сравните два операнда, используя их абстрактное представление, а не их значение, как в
compare_total()
, но игнорируя знак каждого операнда.x.compare_total_mag(y)
эквивалентноx.copy_abs().compare_total(y.copy_abs())
.Эта операция не зависит от контекста и выполняется без проблем: никакие флаги не меняются и округление не выполняется. В качестве исключения версия C может вызвать недействительную операцию, если второй операнд не может быть преобразован точно.
- conjugate()¶
Просто возвращает self, этот метод предназначен только для соответствия спецификации Decimal.
- copy_abs()¶
Возвращает абсолютное значение аргумента. Контекст не влияет на эту операцию, и она выполняется без проблем: флажки не меняются, округление не выполняется.
- copy_negate()¶
Возвращает отрицание аргумента. Контекст не влияет на эту операцию, и она выполняется автоматически: флажки не меняются, округление не выполняется.
- copy_sign(other, context=None)¶
Возвращает копию первого операнда со знаком, совпадающим со знаком второго операнда. Например:
>>> Decimal('2.3').copy_sign(Decimal('-1.5')) Decimal('-2.3')
Эта операция не зависит от контекста и выполняется без проблем: никакие флаги не меняются и округление не выполняется. В качестве исключения версия C может вызвать недействительную операцию, если второй операнд не может быть преобразован точно.
- exp(context=None)¶
Возвращает значение (естественной) экспоненциальной функции
e**x
с заданным числом. Результат округляется правильно с использованием режима округленияROUND_HALF_EVEN
.>>> Decimal(1).exp() Decimal('2.718281828459045235360287471') >>> Decimal(321).exp() Decimal('2.561702493119680037517373933E+139')
- classmethod from_float(f)¶
Альтернативный конструктор, который принимает только экземпляры
float
илиint
.Обратите внимание, что
Decimal.from_float(0.1)
- это не то же самое, чтоDecimal('0.1')
. Поскольку 0.1 не может быть точно представлено в двоичной системе счисления с плавающей запятой, значение сохраняется как ближайшее представимое значение, которым является0x1.999999999999ap-4
. Это эквивалентное значение в десятичной системе счисления равно0.1000000000000000055511151231257827021181583404541015625
.Примечание
Начиная с версии Python 3.2, экземпляр
Decimal
также может быть создан непосредственно изfloat
.>>> Decimal.from_float(0.1) Decimal('0.1000000000000000055511151231257827021181583404541015625') >>> Decimal.from_float(float('nan')) Decimal('NaN') >>> Decimal.from_float(float('inf')) Decimal('Infinity') >>> Decimal.from_float(float('-inf')) Decimal('-Infinity')
Добавлено в версии 3.1.
- fma(other, third, context=None)¶
Слитное умножение-сложение. Возвращаем self*other+third без округления промежуточного результата self*other.
>>> Decimal(2).fma(3, 5) Decimal('11')
- is_canonical()¶
Возвращает
True
, если аргумент является каноническим, иFalse
в противном случае. В настоящее время экземплярDecimal
всегда является каноническим, поэтому эта операция всегда возвращаетTrue
.
- is_finite()¶
Возвращает
True
, если аргументом является конечное число, иFalse
, если аргументом является бесконечность или NaN.
- is_infinite()¶
Возвращает
True
, если аргумент равен положительной или отрицательной бесконечности, иFalse
в противном случае.
- is_nan()¶
Возвращает
True
, если аргументом является NaN (тихий или сигнальный), иFalse
в противном случае.
- is_normal(context=None)¶
Возвращает
True
, если аргумент является нормальным конечным числом. ВозвращаетFalse
, если аргумент равен нулю, ненормален, бесконечен или равен NaN.
- is_qnan()¶
Возвращает
True
, если аргументом является тихое значение NaN, иFalse
в противном случае.
- is_signed()¶
Возвращает
True
, если аргумент имеет отрицательный знак, иFalse
в противном случае. Обратите внимание, что и нули, и NAN могут содержать знаки.
- is_snan()¶
Возвращает
True
, если аргумент является сигнальным значением NaN, иFalse
в противном случае.
- is_subnormal(context=None)¶
Возвращает
True
, если аргумент является ненормальным, иFalse
в противном случае.
- is_zero()¶
Возвращает
True
, если аргумент равен (положительному или отрицательному) нулю, иFalse
в противном случае.
- ln(context=None)¶
Возвращает натуральный логарифм (с основанием e) операнда. Результат округляется правильно с использованием режима округления
ROUND_HALF_EVEN
.
- log10(context=None)¶
Возвращает десятичный логарифм операнда по основанию. Результат округляется правильно с использованием режима округления
ROUND_HALF_EVEN
.
- logb(context=None)¶
Для ненулевого числа верните скорректированный показатель степени его операнда в виде
Decimal
. Если операнд равен нулю, то возвращаетсяDecimal('-Infinity')
и поднимается флагDivisionByZero
. Если операнд равен бесконечности, то возвращаетсяDecimal('Infinity')
.
- logical_and(other, context=None)¶
logical_and()
- это логическая операция, которая принимает два логических операнда (см. Логические операнды). Результатом являетсяand
из двух операндов в цифровом виде.
- logical_invert(context=None)¶
logical_invert()
- это логическая операция. Результатом является инверсия операнда в цифровом виде.
- logical_or(other, context=None)¶
logical_or()
- это логическая операция, которая принимает два логических операнда (см. Логические операнды). Результатом являетсяor
из двух операндов в цифровом виде.
- logical_xor(other, context=None)¶
logical_xor()
- это логическая операция, которая принимает два логических операнда (см. Логические операнды). Результатом является однозначное исключающее или из двух операндов.
- max(other, context=None)¶
Аналогично
max(self, other)
, за исключением того, что перед возвратом применяется правило округления контекста и что значенияNaN
либо сигнализируются, либо игнорируются (в зависимости от контекста и от того, являются ли они сигнальными или тихими).
- max_mag(other, context=None)¶
Аналогично методу
max()
, но сравнение производится с использованием абсолютных значений операндов.
- min(other, context=None)¶
Аналогично
min(self, other)
, за исключением того, что перед возвратом применяется правило округления контекста и что значенияNaN
либо сигнализируются, либо игнорируются (в зависимости от контекста и от того, являются ли они сигнальными или тихими).
- min_mag(other, context=None)¶
Аналогично методу
min()
, но сравнение производится с использованием абсолютных значений операндов.
- next_minus(context=None)¶
Возвращает наибольшее число, представимое в данном контексте (или в контексте текущего потока, если контекст не задан), которое меньше заданного операнда.
- next_plus(context=None)¶
Возвращает наименьшее число, представимое в данном контексте (или в контексте текущего потока, если контекст не задан), которое больше заданного операнда.
- next_toward(other, context=None)¶
Если два операнда неравны, верните число, ближайшее к первому операнду в направлении второго операнда. Если оба операнда численно равны, верните копию первого операнда со знаком, который должен совпадать со знаком второго операнда.
- normalize(context=None)¶
Используется для получения канонических значений класса эквивалентности либо в текущем контексте, либо в указанном контексте.
Это имеет ту же семантику, что и операция «унарный плюс», за исключением того, что если конечный результат конечен, то он приводится к своей простейшей форме с удалением всех конечных нулей и сохранением знака. То есть, если коэффициент отличен от нуля и кратен десяти, коэффициент делится на десять, а показатель степени увеличивается на 1. В противном случае (если коэффициент равен нулю) показатель степени устанавливается равным 0. Во всех случаях знак остается неизменным.
Например,
Decimal('32.100')
иDecimal('0.321000e+2')
нормализуются к эквивалентному значениюDecimal('32.1')
.Обратите внимание, что округление применяется перед приведением к простейшей форме.
В последних версиях спецификации эта операция также известна как
reduce
.
- number_class(context=None)¶
Возвращает строку, описывающую класс операнда. Возвращаемое значение является одной из следующих десяти строк.
"-Infinity"
, указывающий на то, что операнд равен отрицательной бесконечности."-Normal"
, указывающий на то, что операнд является отрицательным нормальным числом."-Subnormal"
, указывающий на то, что операнд является отрицательным и ненормальным."-Zero"
, указывающий на то, что операнд равен отрицательному нулю."+Zero"
, указывающий на то, что операнд равен положительному нулю."+Subnormal"
, указывающий на то, что операнд является положительным и ненормальным."+Normal"
, указывающий на то, что операнд является положительным нормальным числом."+Infinity"
, указывающий на то, что операнд равен положительной бесконечности."NaN"
, указывающий на то, что операнд является тихим NaN (не числом)."sNaN"
, указывающий на то, что операнд является сигнальным NaN.
- quantize(exp, rounding=None, context=None)¶
Возвращает значение, равное первому операнду после округления и имеющее показатель степени второго операнда.
>>> Decimal('1.41421356').quantize(Decimal('1.000')) Decimal('1.414')
В отличие от других операций, если длина коэффициента после операции квантования превышает точность, то выдается сигнал
InvalidOperation
. Это гарантирует, что, если нет условия ошибки, квантованный показатель степени всегда равен показателю правого операнда.Кроме того, в отличие от других операций, квантование никогда не сигнализирует о недостаточном потоке, даже если результат является ненормальным и неточным.
Если показатель степени второго операнда больше, чем у первого, то может потребоваться округление. В этом случае режим округления определяется аргументом
rounding
, если он задан, в противном случае - аргументомcontext
; если ни один из аргументов не задан, используется режим округления контекста текущего потока.Ошибка возвращается всякий раз, когда результирующий показатель больше
Emax
или меньшеEtiny()
.
- radix()¶
Возвращает
Decimal(10)
, основание, в котором классDecimal
выполняет все свои арифметические действия. Включено для обеспечения совместимости со спецификацией.
- remainder_near(other, context=None)¶
Возвращает остаток от деления self на other. Это отличается от
self % other
тем, что знак остатка выбран таким образом, чтобы минимизировать его абсолютное значение. Точнее, возвращаемое значение равноself - n * other
, гдеn
- это целое число, наиболее близкое к точному значениюself / other
, и если два целых числа одинаково близки, то выбирается четное.Если результат равен нулю, то его знаком будет знак self.
>>> Decimal(18).remainder_near(Decimal(10)) Decimal('-2') >>> Decimal(25).remainder_near(Decimal(10)) Decimal('5') >>> Decimal(35).remainder_near(Decimal(10)) Decimal('-5')
- rotate(other, context=None)¶
Возвращает результат преобразования цифр первого операнда на величину, указанную вторым операндом. Второй операнд должен быть целым числом в диапазоне от точности до прецизионности. Абсолютное значение второго операнда указывает количество позиций, которые необходимо изменить. Если второй операнд положительный, то выполняется поворот влево; в противном случае выполняется поворот вправо. Коэффициент первого операнда при необходимости дополняется слева нулями с точностью до длины. Знак и показатель степени первого операнда остаются неизменными.
- same_quantum(other, context=None)¶
Проверьте, имеют ли self и other одинаковый показатель или оба они равны
NaN
.Эта операция не зависит от контекста и выполняется без проблем: никакие флаги не меняются и округление не выполняется. В качестве исключения версия C может вызвать недействительную операцию, если второй операнд не может быть преобразован точно.
- scaleb(other, context=None)¶
Возвращает первый операнд с показателем степени, измененным на второй. Аналогично, возвращает первый операнд, умноженный на
10**other
. Второй операнд должен быть целым числом.
- shift(other, context=None)¶
Возвращает результат сдвига цифр первого операнда на величину, указанную вторым операндом. Второй операнд должен быть целым числом в диапазоне от точности до прецизионности. Абсолютное значение второго операнда указывает количество позиций, на которые необходимо произвести сдвиг. Если второй операнд положительный, то происходит сдвиг влево, в противном случае - вправо. Цифры, сдвинутые в коэффициент, равны нулю. Знак и показатель степени первого операнда не изменяются.
- sqrt(context=None)¶
Верните квадратный корень из аргумента с полной точностью.
- to_eng_string(context=None)¶
Преобразуйте в строку, используя инженерную нотацию, если требуется показатель степени.
В инженерных обозначениях используется показатель степени, кратный 3. При этом слева от десятичного знака может оставаться до 3 цифр и может потребоваться добавление одного или двух завершающих нулей.
Например, это преобразует
Decimal('123E+1')
вDecimal('1.23E+3')
.
- to_integral(rounding=None, context=None)¶
Идентичен методу
to_integral_value()
. Названиеto_integral
сохранено для совместимости со старыми версиями.
- to_integral_exact(rounding=None, context=None)¶
Округлить до ближайшего целого числа, указав
Inexact
илиRounded
соответственно, если происходит округление. Режим округления определяется параметромrounding
, если он задан, в противном случае - параметромcontext
. Если ни один из параметров не задан, то используется режим округления для текущего контекста.
Логические операнды¶
Методы logical_and()
, logical_invert()
, logical_or()
, и logical_xor()
ожидают, что их аргументами будут логические операнды. Логический операнд* - это экземпляр Decimal
, показатель степени и знак которого равны нулю, а все цифры равны либо 0
, либо 1
.
Контекстные объекты¶
Контексты - это среда для арифметических операций. Они определяют точность, устанавливают правила округления, определяют, какие сигналы рассматриваются как исключения, и ограничивают диапазон значений экспонент.
Каждый поток имеет свой собственный текущий контекст, доступ к которому или изменение которого осуществляется с помощью функций getcontext()
и setcontext()
:
- decimal.getcontext()¶
Возвращает текущий контекст для активного потока.
- decimal.setcontext(c)¶
Установите текущий контекст для активного потока равным c.
Вы также можете использовать инструкцию with
и функцию localcontext()
для временного изменения активного контекста.
- decimal.localcontext(ctx=None, \*\*kwargs)¶
Возвращает диспетчер контекста, который устанавливает текущий контекст для активного потока в качестве копии ctx при входе в with-statement и восстанавливает предыдущий контекст при выходе из with-statement. Если контекст не указан, используется копия текущего контекста. Аргумент kwargs используется для задания атрибутов нового контекста.
Например, следующий код устанавливает текущую десятичную точность в 42 знака, выполняет вычисление, а затем автоматически восстанавливает предыдущий контекст:
from decimal import localcontext with localcontext() as ctx: ctx.prec = 42 # Perform a high precision calculation s = calculate_something() s = +s # Round the final result back to the default precision
Используя аргументы ключевого слова, код будет выглядеть следующим образом:
from decimal import localcontext with localcontext(prec=42) as ctx: s = calculate_something() s = +s
Вызывает
TypeError
, если kwargs предоставляет атрибут, которыйContext
не поддерживается. Вызывает либоTypeError
, либоValueError
, если kwargs предоставляет недопустимое значение для атрибута.Изменено в версии 3.11:
localcontext()
теперь поддерживается настройка атрибутов контекста с помощью аргументов ключевых слов.
Новые контексты также могут быть созданы с помощью конструктора Context
, описанного ниже. Кроме того, модуль предоставляет три готовых контекста:
- class decimal.BasicContext¶
Это стандартный контекст, определенный общей спецификацией десятичной арифметики. Точность задана равной девяти. Округление задано равным
ROUND_HALF_UP
. Все флажки сняты. Все ловушки активированы (рассматриваются как исключения), за исключениемInexact
,Rounded
, иSubnormal
.Поскольку многие ловушки включены, этот контекст полезен для отладки.
- class decimal.ExtendedContext¶
Это стандартный контекст, определенный общей спецификацией десятичной арифметики. Точность задана равной девяти. Округление задано равным
ROUND_HALF_EVEN
. Все флажки сброшены. Ловушки не включены (чтобы во время вычислений не возникали исключения).Поскольку ловушки отключены, этот контекст полезен для приложений, которые предпочитают получать значение результата
NaN
илиInfinity
вместо того, чтобы создавать исключения. Это позволяет приложению завершить запуск при наличии условий, которые в противном случае остановили бы программу.
- class decimal.DefaultContext¶
Этот контекст используется конструктором
Context
в качестве прототипа для новых контекстов. Изменение поля (с такой точностью) приводит к изменению значения по умолчанию для новых контекстов, созданных конструкторомContext
.Этот контекст наиболее полезен в многопоточных средах. Изменение одного из полей перед запуском потоков приводит к установке общесистемных значений по умолчанию. Изменение полей после запуска потоков не рекомендуется, так как для предотвращения «гонки» потребуется синхронизация потоков.
В однопоточных средах предпочтительнее вообще не использовать этот контекст. Вместо этого просто создайте контексты явно, как описано ниже.
Значениями по умолчанию являются
Context.prec
=28
,Context.rounding
=ROUND_HALF_EVEN
, и включенные ловушки дляOverflow
,InvalidOperation
, иDivisionByZero
.
В дополнение к трем предоставленным контекстам с помощью конструктора Context
можно создать новые контексты.
- class decimal.Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)¶
Создает новый контекст. Если поле не указано или имеет значение
None
, значения по умолчанию копируются из поляDefaultContext
. Если поле flags не указано или имеет значениеNone
, все флажки снимаются.prec - это целое число в диапазоне [
1
,MAX_PREC
], которое задает точность для арифметических операций в контексте.Параметр округление является одной из констант, перечисленных в разделе Rounding Modes.
В полях traps и flags указаны все сигналы, которые необходимо установить. Как правило, в новых контекстах следует устанавливать только ловушки и не указывать флаги.
Поля Emin и Emax представляют собой целые числа, определяющие внешние пределы, допустимые для показателей степени. Emin должно быть в диапазоне [
MIN_EMIN
,0
], * Emax* в диапазоне [0
,MAX_EMAX
].Поле заглавные буквы имеет значение либо
0
, либо1
(по умолчанию). Если задано значение1
, показатели степени печатаются с прописной буквыE
; в противном случае используется строчная букваe
:Decimal('6.02e+23')
.Поле clamp имеет значение либо
0
(по умолчанию), либо1
. Если задано значение1
, показатель степениe
экземпляраDecimal
, представимого в этом контексте, строго ограничен диапазономEmin - prec + 1 <= e <= Emax - prec + 1
. Если значение clamp равно0
, то выполняется более слабое условие: скорректированный показатель степени экземпляраDecimal
не болееEmax
. Когда clamp равен1
, у большого нормального числа, где это возможно, будет уменьшен показатель степени и к его коэффициенту добавлено соответствующее количество нулей, чтобы соответствовать ограничениям на показатель степени; при этом сохраняется значение числа, но теряется информация о значимых конечных нулях. Например:>>> Context(prec=6, Emax=999, clamp=1).create_decimal('1.23e999') Decimal('1.23000E+999')
Фиксированное значение
1
обеспечивает совместимость с десятичными форматами обмена с фиксированной шириной, указанными в IEEE 754.Класс
Context
определяет несколько методов общего назначения, а также большое количество методов для непосредственного выполнения арифметических операций в заданном контексте. Кроме того, для каждого из методовDecimal
, описанных выше (за исключением методовadjusted()
иas_tuple()
), существует соответствующий методContext
. Например, для экземпляраContext
C
и экземпляраDecimal
x
,C.exp(x)
эквивалентноx.exp(context=C)
. Каждый методContext
принимает целое число Python (экземплярint
) везде, где допускается десятичный экземпляр.- clear_flags()¶
Сбрасывает все флаги на
0
.
- clear_traps()¶
Сбрасывает все ловушки на
0
.Добавлено в версии 3.3.
- copy()¶
Возвращает дубликат контекста.
- copy_decimal(num)¶
Возвращает копию десятичного номера экземпляра.
- create_decimal(num)¶
Создает новый десятичный экземпляр из num, но использует self в качестве контекста. В отличие от конструктора
Decimal
, к преобразованию применяются точность контекста, метод округления, флаги и ловушки.Это полезно, поскольку константы часто задаются с большей точностью, чем требуется приложению. Еще одно преимущество заключается в том, что округление немедленно устраняет нежелательные эффекты от цифр, превышающих текущую точность. В следующем примере использование некругленных входных данных означает, что добавление нуля к сумме может изменить результат:
>>> getcontext().prec = 3 >>> Decimal('3.4445') + Decimal('1.0023') Decimal('4.45') >>> Decimal('3.4445') + Decimal(0) + Decimal('1.0023') Decimal('4.44')
Этот метод реализует операцию преобразования в число, описанную в спецификации IBM. Если аргументом является строка, то начальные и конечные пробелы и подчеркивания не допускаются.
- create_decimal_from_float(f)¶
Создает новый десятичный экземпляр из числа с плавающей запятой f, но округляет с использованием self в качестве контекста. В отличие от метода класса
Decimal.from_float()
, к преобразованию применяются точность контекста, метод округления, флаги и ловушки.>>> context = Context(prec=5, rounding=ROUND_DOWN) >>> context.create_decimal_from_float(math.pi) Decimal('3.1415') >>> context = Context(prec=5, traps=[Inexact]) >>> context.create_decimal_from_float(math.pi) Traceback (most recent call last): ... decimal.Inexact: None
Добавлено в версии 3.1.
- Etiny()¶
Возвращает значение, равное
Emin - prec + 1
, которое является минимальным значением показателя для результатов, отличных от нормальных. При возникновении неполадок показатель устанавливается равнымEtiny
.
- Etop()¶
Возвращает значение, равное
Emax - prec + 1
.
Обычный подход к работе с десятичными дробями заключается в создании экземпляров
Decimal
и последующем применении арифметических операций, которые выполняются в текущем контексте для активного потока. Альтернативный подход заключается в использовании контекстных методов для вычисления в определенном контексте. Методы аналогичны методам для классаDecimal
и описаны здесь лишь вкратце.- abs(x)¶
Возвращает абсолютное значение x.
- add(x, y)¶
Возвращает сумму значений x и y.
- canonical(x)¶
Возвращает тот же десятичный объект x.
- compare(x, y)¶
Сравнивает x и y численно.
- compare_signal(x, y)¶
Сравнивает значения двух операндов численно.
- compare_total(x, y)¶
Сравнивает два операнда, используя их абстрактное представление.
- compare_total_mag(x, y)¶
Сравнивает два операнда, используя их абстрактное представление, игнорируя знак.
- copy_abs(x)¶
Возвращает копию x со знаком, равным 0.
- copy_negate(x)¶
Возвращает копию x с перевернутым знаком.
- copy_sign(x, y)¶
Копирует знак из y в x.
- divide(x, y)¶
Возвращает x, деленное на y.
- divide_int(x, y)¶
Возвращает x, разделенное на y, усеченное до целого числа.
- divmod(x, y)¶
Делит два числа и возвращает целую часть результата.
- exp(x)¶
Возвращает
e ** x
.
- fma(x, y, z)¶
Возвращает x, умноженное на y, плюс z.
- is_canonical(x)¶
Возвращает
True
, если x является каноническим; в противном случае возвращаетFalse
.
- is_finite(x)¶
Возвращает
True
, если x конечно; в противном случае возвращаетFalse
.
- is_infinite(x)¶
Возвращает
True
, если x бесконечно; в противном случае возвращаетFalse
.
- is_nan(x)¶
Возвращает
True
, если x является QNaN или SNaN; в противном случае возвращаетFalse
.
- is_normal(x)¶
Возвращает
True
, если x - обычное число; в противном случае возвращаетFalse
.
- is_qnan(x)¶
Возвращает
True
, если x - тихое значение NaN; в противном случае возвращаетFalse
.
- is_signed(x)¶
Возвращает
True
, если значение x отрицательное; в противном случае возвращаетFalse
.
- is_snan(x)¶
Возвращает
True
, если x является сигнальным значением NaN; в противном случае возвращаетFalse
.
- is_subnormal(x)¶
Возвращает
True
, если значение x ниже нормы; в противном случае возвращаетFalse
.
- is_zero(x)¶
Возвращает
True
, если x равно нулю; в противном случае возвращаетFalse
.
- ln(x)¶
Возвращает натуральный (по основанию e) логарифм x.
- log10(x)¶
Возвращает логарифм x по основанию 10.
- logb(x)¶
Возвращает показатель степени величины операндов MSD.
- logical_and(x, y)¶
Применяет логическую операцию и между цифрами каждого операнда.
- logical_invert(x)¶
Инвертируйте все цифры в x.
- logical_or(x, y)¶
Применяет логическую операцию или между цифрами каждого операнда.
- logical_xor(x, y)¶
Применяет логическую операцию xor между цифрами каждого операнда.
- max(x, y)¶
Сравнивает два значения численно и возвращает максимальное значение.
- max_mag(x, y)¶
Сравнивает значения численно, при этом их знак игнорируется.
- min(x, y)¶
Сравнивает два значения численно и возвращает минимальное значение.
- min_mag(x, y)¶
Сравнивает значения численно, при этом их знак игнорируется.
- minus(x)¶
Minus соответствует унарному префиксному оператору minus в Python.
- multiply(x, y)¶
Верните товар x и y.
- next_minus(x)¶
Возвращает наибольшее представимое число, меньшее, чем x.
- next_plus(x)¶
Возвращает наименьшее представимое число, большее, чем x.
- next_toward(x, y)¶
Возвращает число, наиболее близкое к x, в направлении к y.
- normalize(x)¶
Сводит x к его простейшей форме.
- number_class(x)¶
Возвращает указание на класс x.
- plus(x)¶
Plus соответствует оператору plus с унарным префиксом в Python. Эта операция применяет контекстную точность и округление, поэтому она не является операцией идентификации.
- power(x, y, modulo=None)¶
Возвращает
x
в степеньy
, уменьшенную по модулюmodulo
, если задано.Используя два аргумента, вычислите
x**y
. Еслиx
отрицательное значение, тоy
должно быть целым числом. Результат будет неточным, если толькоy
не является целым числом, а результат конечен и может быть выражен точно в цифрах «precision». Используется режим округления контекста. В версии Python результаты всегда правильно округляются.Decimal(0) ** Decimal(0)
приводит кInvalidOperation
, и еслиInvalidOperation
не захвачен, то приводит кDecimal('NaN')
.Изменено в версии 3.3: Модуль C вычисляет
power()
в терминах правильно округленных функцийexp()
иln()
. Результат хорошо определен, но только «почти всегда правильно округлен».Используя три аргумента, вычислите
(x**y) % modulo
. Для формы с тремя аргументами сохраняются следующие ограничения на аргументы:все три аргумента должны быть целыми
y
должно быть неотрицательнымпо крайней мере, одно из значений
x
илиy
должно быть ненулевымmodulo
должно быть ненулевым и содержать не более цифр «точности»
Значение, полученное в результате
Context.power(x, y, modulo)
, равно значению, которое было бы получено при вычислении(x**y) % modulo
с неограниченной точностью, но вычисляется более эффективно. Показатель результата равен нулю, независимо от значений показателейx
,y
иmodulo
. Результат всегда точный.
- quantize(x, y)¶
Возвращает значение, равное x (округленное), с показателем степени y.
- radix()¶
Просто возвращает 10, так как это десятичное число, :)
- remainder(x, y)¶
Возвращает остаток от целочисленного деления.
Знак результата, если он отличен от нуля, совпадает со знаком первоначального дивиденда.
- remainder_near(x, y)¶
Возвращает
x - y * n
, где n - целое число, наиболее близкое к точному значениюx / y
(если результат равен 0, то его знаком будет знак x).
- rotate(x, y)¶
Возвращает повернутую копию в x, y раз.
- same_quantum(x, y)¶
Возвращает
True
, если два операнда имеют одинаковый показатель степени.
- scaleb(x, y)¶
Возвращает первый операнд после добавления второго значения exp.
- shift(x, y)¶
Возвращает сдвинутую копию в x, y раз.
- sqrt(x)¶
Квадратный корень из неотрицательного числа с точностью до контекста.
- subtract(x, y)¶
Возвращает разницу между x и y.
- to_eng_string(x)¶
Преобразуйте в строку, используя инженерную нотацию, если требуется показатель степени.
В инженерных обозначениях используется показатель степени, кратный 3. При этом слева от десятичного знака может оставаться до 3 цифр и может потребоваться добавление одного или двух завершающих нулей.
- to_integral_exact(x)¶
Округляет до целого числа.
- to_sci_string(x)¶
Преобразует число в строку с использованием научной нотации.
Константы¶
Приведенные в этом разделе константы применимы только к модулю C. Они также включены в чистую версию Python для обеспечения совместимости.
32-разрядный |
64-разрядный |
|
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
- decimal.HAVE_THREADS¶
Значение
True
. Устарело, потому что в Python теперь всегда есть потоки.
Не рекомендуется, начиная с версии 3.9.
- decimal.HAVE_CONTEXTVAR¶
Значение по умолчанию -
True
. Если значение Python равноconfigured using the --without-decimal-contextvar option
, то версия C использует локальный контекст потока, а не локальный контекст сопрограммы, и значение равноFalse
. В некоторых сценариях с вложенным контекстом это происходит немного быстрее.
Добавлено в версии 3.8.3.
Режимы округления¶
- decimal.ROUND_CEILING¶
Округлите в направлении
Infinity
.
- decimal.ROUND_DOWN¶
Округлите до нуля.
- decimal.ROUND_FLOOR¶
Округлите в направлении
-Infinity
.
- decimal.ROUND_HALF_DOWN¶
Раунд за ближайшим, ничьи приближаются к нулю.
- decimal.ROUND_HALF_EVEN¶
Округление до ближайшего с привязкой к ближайшему четному целому числу.
- decimal.ROUND_HALF_UP¶
Раунд за раундом до ближайшего, при равенстве очков, отличающемся от нуля.
- decimal.ROUND_UP¶
Округлите от нуля.
- decimal.ROUND_05UP¶
Округлите от нуля, если последняя цифра после округления в сторону нуля была бы равна 0 или 5; в противном случае округлите в сторону нуля.
Сигналы¶
Сигналы представляют условия, возникающие во время вычислений. Каждый из них соответствует одному контекстному флагу и одному активатору контекстной ловушки.
Контекстный флаг устанавливается всякий раз, когда выполняется условие. После вычисления флажки могут быть проверены в информационных целях (например, чтобы определить, было ли вычисление точным). После проверки флажков обязательно снимите все флажки перед началом следующего вычисления.
Если для сигнала установлен параметр contexts trap enabler, то условие вызывает возникновение исключения Python. Например, если установлен параметр DivisionByZero
, то при выполнении условия возникает исключение DivisionByZero
.
- class decimal.Clamped¶
Изменил показатель степени, чтобы он соответствовал ограничениям представления.
Как правило, ограничение происходит, когда показатель степени выходит за пределы контекстов
Emin
иEmax
. Если возможно, показатель степени приводится в соответствие путем добавления нулей к коэффициенту.
- class decimal.DecimalException¶
Базовый класс для других сигналов и подкласс
ArithmeticError
.
- class decimal.DivisionByZero¶
Сигнализирует о делении не бесконечного числа на ноль.
Может возникать при делении, делении по модулю или при возведении числа в отрицательную степень. Если этот сигнал не перехватывается, возвращает
Infinity
или-Infinity
со знаком, определенным входными данными для вычисления.
- class decimal.Inexact¶
Указывает, что произошло округление и результат не является точным.
Сигнализирует о том, что при округлении были отброшены ненулевые цифры. Возвращается округленный результат. Сигнальный флажок или ловушка используются для определения неточности результатов.
- class decimal.InvalidOperation¶
Была выполнена недопустимая операция.
Указывает, что была запрошена операция, которая не имеет смысла. Если не зафиксирована, возвращает
NaN
. Возможные причины включают:Infinity - Infinity 0 * Infinity Infinity / Infinity x % 0 Infinity % x sqrt(-x) and x > 0 0 ** 0 x ** (non-integer) x ** Infinity
- class decimal.Overflow¶
Числовое переполнение.
Указывает, что показатель степени после округления стал больше, чем
Context.Emax
. Если он не зафиксирован, результат зависит от режима округления, при котором либо значение округляется внутрь до наибольшего представимого конечного числа, либо значение округляется наружу доInfinity
. В любом случае также сигнализируютсяInexact
иRounded
.
- class decimal.Rounded¶
Произошло округление, хотя, возможно, никакая информация не была потеряна.
Сигнализируется всякий раз, когда при округлении цифры отбрасываются, даже если эти цифры равны нулю (например, при округлении от
5.00
до5.0
). Если не зафиксировано, возвращает результат без изменений. Этот сигнал используется для обнаружения потери значащих цифр.
- class decimal.Subnormal¶
Показатель степени был ниже
Emin
до округления.Возникает, когда результат операции не соответствует норме (показатель степени слишком мал). Если не зафиксирован, возвращает результат без изменений.
- class decimal.Underflow¶
Численный расход с округлением результата до нуля.
Возникает, когда ненормальный результат округляется до нуля. Также отображаются
Inexact
иSubnormal
.
- class decimal.FloatOperation¶
Включите более строгую семантику для смешивания чисел с плавающей запятой и десятичных дробей.
Если сигнал не перехвачен (по умолчанию), в конструкторе
Decimal
,create_decimal()
и во всех операторах сравнения допускается смешивание чисел с плавающей запятой и десятичных дробей. Как преобразование, так и сравнение являются точными. Любое выполнение смешанной операции автоматически регистрируется путем установкиFloatOperation
в контекстных флагах. При явных преобразованиях с помощьюfrom_float()
илиcreate_decimal_from_float()
флаг не устанавливается.В противном случае (сигнал перехватывается) не выполняются только сравнения на равенство и явные преобразования. Все остальные смешанные операции приводят к
FloatOperation
.
В следующей таблице представлена краткая информация об иерархии сигналов:
exceptions.ArithmeticError(exceptions.Exception)
DecimalException
Clamped
DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
Inexact
Overflow(Inexact, Rounded)
Underflow(Inexact, Rounded, Subnormal)
InvalidOperation
Rounded
Subnormal
FloatOperation(DecimalException, exceptions.TypeError)
Заметки с плавающей запятой¶
Уменьшение ошибки округления с повышенной точностью¶
Использование десятичной системы счисления с плавающей запятой устраняет ошибку десятичного представления (позволяя точно представлять 0.1
); однако при выполнении некоторых операций все еще может возникать ошибка округления, когда ненулевые цифры превышают фиксированную точность.
Эффект ошибки округления может быть усилен сложением или вычитанием почти одинаковых величин, что приводит к потере значимости. Кнут приводит два поучительных примера, в которых арифметика округления с плавающей запятой с недостаточной точностью приводит к нарушению ассоциативных и дистрибутивных свойств сложения:
# Examples from Seminumerical Algorithms, Section 4.2.2.
>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 8
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.5111111')
>>> u + (v + w)
Decimal('10')
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.01')
>>> u * (v+w)
Decimal('0.0060000')
Модуль decimal
позволяет восстанавливать идентификаторы, повышая точность в достаточной степени, чтобы избежать потери значимости:
>>> getcontext().prec = 20
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.51111111')
>>> u + (v + w)
Decimal('9.51111111')
>>>
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.0060000')
>>> u * (v+w)
Decimal('0.0060000')
Особые ценности¶
Система счисления для модуля decimal
содержит специальные значения, включая NaN
, sNaN
, -Infinity
, Infinity
, и два нуля, +0
и -0
.
Значения бесконечности могут быть получены непосредственно с помощью: Decimal('Infinity')
. Кроме того, они могут возникать в результате деления на ноль, когда сигнал DivisionByZero
не перехватывается. Аналогично, когда сигнал Overflow
не улавливается, округление до бесконечности может привести к превышению пределов наибольшего представимого числа.
Бесконечности являются знаковыми (аффинными) и могут использоваться в арифметических операциях, где они рассматриваются как очень большие неопределенные числа. Например, добавление константы к бесконечности дает еще один бесконечный результат.
Некоторые операции являются неопределенными и возвращают NaN
, или, если сигнал InvalidOperation
перехвачен, возникает исключение. Например, 0/0
возвращает NaN
, что означает «не число». Эта разновидность NaN
является тихой и, будучи однажды созданной, будет проходить через другие вычисления, всегда приводящие к другой NaN
. Такое поведение может быть полезно для серии вычислений, в которых иногда отсутствуют входные данные - это позволяет продолжить вычисление, помечая конкретные результаты как недопустимые.
Возможен вариант sNaN
, который подает сигнал, а не сохраняет молчание после каждой операции. Это полезное возвращаемое значение, когда при получении недопустимого результата необходимо прервать вычисление для специальной обработки.
Поведение операторов сравнения в Python может быть немного неожиданным, когда речь идет о NaN
. Тест на равенство, где один из операндов является тихим или сигнализирующим NaN
, всегда возвращает False
(даже при выполнении Decimal('NaN')==Decimal('NaN')
), в то время как тест на неравенство всегда возвращает True
. Попытка сравнить две десятичные дроби с помощью любого из операторов <
, <=
, >
или >=
вызовет сигнал InvalidOperation
, если любой из операндов является NaN
, и верните False
, если этот сигнал не перехвачен. Обратите внимание, что общая спецификация десятичной арифметики не определяет поведение прямых сравнений; эти правила для сравнений, включающих NaN
, были взяты из стандарта IEEE 854 (см. таблицу 3 в разделе 5.7). Чтобы обеспечить строгое соответствие стандартам, используйте вместо этого методы compare()
и compare_signal()
.
Нули со знаком могут быть результатом неполных вычислений. Они сохраняют знак, который был бы получен, если бы вычисления были выполнены с большей точностью. Поскольку их величина равна нулю, как положительные, так и отрицательные нули рассматриваются как равные, а их знак является информационным.
В дополнение к двум нулям со знаком, которые различны, но равны, существуют различные представления нуля с разной точностью, но эквивалентные по значению. К этому нужно немного привыкнуть. Для глаза, привыкшего к нормализованным представлениям с плавающей запятой, не сразу очевидно, что следующее вычисление возвращает значение, равное нулю:
>>> 1 / Decimal('Infinity')
Decimal('0E-1000026')
Работа с потоками¶
Функция getcontext()
обращается к другому объекту Context
для каждого потока. Наличие отдельных контекстов потоков означает, что потоки могут вносить изменения (например, getcontext().prec=10
), не вмешиваясь в работу других потоков.
Аналогично, функция setcontext()
автоматически назначает свой целевой объект текущему потоку.
Если setcontext()
не вызывался ранее getcontext()
, то getcontext()
автоматически создаст новый контекст для использования в текущем потоке.
Новый контекст копируется из прототипа контекста, называемого defaultContext. Чтобы управлять значениями по умолчанию, чтобы каждый поток использовал одни и те же значения во всем приложении, непосредственно измените объект defaultContext. Это должно быть сделано до запуска любых потоков, чтобы не возникало состояния гонки между потоками, вызывающими getcontext()
. Например:
# Set applicationwide defaults for all threads about to be launched
DefaultContext.prec = 12
DefaultContext.rounding = ROUND_DOWN
DefaultContext.traps = ExtendedContext.traps.copy()
DefaultContext.traps[InvalidOperation] = 1
setcontext(DefaultContext)
# Afterwards, the threads can be started
t1.start()
t2.start()
t3.start()
. . .
Рецепты¶
Вот несколько рецептов, которые служат в качестве вспомогательных функций и демонстрируют способы работы с классом Decimal
:
def moneyfmt(value, places=2, curr='', sep=',', dp='.',
pos='', neg='-', trailneg=''):
"""Convert Decimal to a money formatted string.
places: required number of places after the decimal point
curr: optional currency symbol before the sign (may be blank)
sep: optional grouping separator (comma, period, space, or blank)
dp: decimal point indicator (comma or period)
only specify as blank when places is zero
pos: optional sign for positive numbers: '+', space or blank
neg: optional sign for negative numbers: '-', '(', space or blank
trailneg:optional trailing minus indicator: '-', ')', space or blank
>>> d = Decimal('-1234567.8901')
>>> moneyfmt(d, curr='$')
'-$1,234,567.89'
>>> moneyfmt(d, places=0, sep='.', dp='', neg='', trailneg='-')
'1.234.568-'
>>> moneyfmt(d, curr='$', neg='(', trailneg=')')
'($1,234,567.89)'
>>> moneyfmt(Decimal(123456789), sep=' ')
'123 456 789.00'
>>> moneyfmt(Decimal('-0.02'), neg='<', trailneg='>')
'<0.02>'
"""
q = Decimal(10) ** -places # 2 places --> '0.01'
sign, digits, exp = value.quantize(q).as_tuple()
result = []
digits = list(map(str, digits))
build, next = result.append, digits.pop
if sign:
build(trailneg)
for i in range(places):
build(next() if digits else '0')
if places:
build(dp)
if not digits:
build('0')
i = 0
while digits:
build(next())
i += 1
if i == 3 and digits:
i = 0
build(sep)
build(curr)
build(neg if sign else pos)
return ''.join(reversed(result))
def pi():
"""Compute Pi to the current precision.
>>> print(pi())
3.141592653589793238462643383
"""
getcontext().prec += 2 # extra digits for intermediate steps
three = Decimal(3) # substitute "three=3.0" for regular floats
lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
while s != lasts:
lasts = s
n, na = n+na, na+8
d, da = d+da, da+32
t = (t * n) / d
s += t
getcontext().prec -= 2
return +s # unary plus applies the new precision
def exp(x):
"""Return e raised to the power of x. Result type matches input type.
>>> print(exp(Decimal(1)))
2.718281828459045235360287471
>>> print(exp(Decimal(2)))
7.389056098930650227230427461
>>> print(exp(2.0))
7.38905609893
>>> print(exp(2+0j))
(7.38905609893+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num = 0, 0, 1, 1, 1
while s != lasts:
lasts = s
i += 1
fact *= i
num *= x
s += num / fact
getcontext().prec -= 2
return +s
def cos(x):
"""Return the cosine of x as measured in radians.
The Taylor series approximation works best for a small value of x.
For larger values, first compute x = x % (2 * pi).
>>> print(cos(Decimal('0.5')))
0.8775825618903727161162815826
>>> print(cos(0.5))
0.87758256189
>>> print(cos(0.5+0j))
(0.87758256189+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num, sign = 0, 0, 1, 1, 1, 1
while s != lasts:
lasts = s
i += 2
fact *= i * (i-1)
num *= x * x
sign *= -1
s += num / fact * sign
getcontext().prec -= 2
return +s
def sin(x):
"""Return the sine of x as measured in radians.
The Taylor series approximation works best for a small value of x.
For larger values, first compute x = x % (2 * pi).
>>> print(sin(Decimal('0.5')))
0.4794255386042030002732879352
>>> print(sin(0.5))
0.479425538604
>>> print(sin(0.5+0j))
(0.479425538604+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1
while s != lasts:
lasts = s
i += 2
fact *= i * (i-1)
num *= x * x
sign *= -1
s += num / fact * sign
getcontext().prec -= 2
return +s
Часто задаваемые вопросы о десятичных дробях¶
В. Набирать decimal.Decimal('1234.5')
неудобно. Есть ли способ минимизировать ввод текста при использовании интерактивного интерпретатора
О. Некоторые пользователи сокращают конструктор до одной буквы:
>>> D = decimal.Decimal
>>> D('1.23') + D('3.45')
Decimal('4.68')
В. В приложении с фиксированной запятой и двумя знаками после запятой некоторые входные данные содержат много знаков после запятой и должны быть округлены. Другие не должны содержать лишних цифр и должны быть проверены. Какие методы следует использовать
О. Метод quantize()
округляет до фиксированного числа знаков после запятой. Если установлен параметр Inexact
, это также полезно для проверки:
>>> TWOPLACES = Decimal(10) ** -2 # same as Decimal('0.01')
>>> # Round to two places
>>> Decimal('3.214').quantize(TWOPLACES)
Decimal('3.21')
>>> # Validate that a number does not exceed two places
>>> Decimal('3.21').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Decimal('3.21')
>>> Decimal('3.214').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Traceback (most recent call last):
...
Inexact: None
В. Как только у меня будут действительные входные данные из двух мест, как мне сохранить этот инвариант во всем приложении
О. Некоторые операции, такие как сложение, вычитание и умножение на целое число, автоматически сохраняют фиксированную точку. Другие операции, такие как деление и нецелочисленное умножение, изменяют количество знаков после запятой и требуют выполнения шага quantize()
.:
>>> a = Decimal('102.72') # Initial fixed-point values
>>> b = Decimal('3.17')
>>> a + b # Addition preserves fixed-point
Decimal('105.89')
>>> a - b
Decimal('99.55')
>>> a * 42 # So does integer multiplication
Decimal('4314.24')
>>> (a * b).quantize(TWOPLACES) # Must quantize non-integer multiplication
Decimal('325.62')
>>> (b / a).quantize(TWOPLACES) # And quantize division
Decimal('0.03')
При разработке приложений с фиксированной точкой удобно определять функции для обработки шага quantize()
:
>>> def mul(x, y, fp=TWOPLACES):
... return (x * y).quantize(fp)
>>> def div(x, y, fp=TWOPLACES):
... return (x / y).quantize(fp)
>>> mul(a, b) # Automatically preserve fixed-point
Decimal('325.62')
>>> div(b, a)
Decimal('0.03')
В. Существует множество способов выразить одно и то же значение. Числа 200
, 200.000
, 2E2
, и .02E+4
имеют одинаковое значение с различной точностью. Есть ли способ преобразовать их в единое узнаваемое каноническое значение
О. Метод normalize()
сопоставляет все эквивалентные значения с одним репрезентативным:
>>> values = map(Decimal, '200 200.000 2E2 .02E+4'.split())
>>> [v.normalize() for v in values]
[Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2')]
В. Когда при вычислении происходит округление
О. Это происходит после вычисления. Философия десятичной спецификации заключается в том, что числа считаются точными и создаются независимо от текущего контекста. Они могут даже обладать большей точностью, чем текущий контекст. Вычисления выполняются с использованием именно этих входных данных, а затем к результату вычисления применяется округление (или другие контекстные операции):
>>> getcontext().prec = 5
>>> pi = Decimal('3.1415926535') # More than 5 digits
>>> pi # All digits are retained
Decimal('3.1415926535')
>>> pi + 0 # Rounded after an addition
Decimal('3.1416')
>>> pi - Decimal('0.00005') # Subtract unrounded numbers, then round
Decimal('3.1415')
>>> pi + 0 - Decimal('0.00005'). # Intermediate values are rounded
Decimal('3.1416')
В. Некоторые десятичные значения всегда выводятся в экспоненциальной записи. Есть ли способ получить неэкспоненциальное представление
О. Для некоторых значений экспоненциальная запись является единственным способом выразить количество значимых позиций в коэффициенте. Например, выражение 5.0E+3
как 5000
сохраняет значение постоянным, но не может показать двухзначное значение оригинала.
Если приложение не заботится об отслеживании значимости, легко удалить экспоненту и конечные нули, потеряв значимость, но сохранив значение неизменным:
>>> def remove_exponent(d):
... return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')
В. Есть ли способ преобразовать обычное число с плавающей точкой в Decimal
О. Да, любое двоичное число с плавающей запятой может быть точно выражено в виде десятичной дроби, хотя точное преобразование может потребовать большей точности, чем подсказывает интуиция:
>>> Decimal(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875')
В. Как я могу убедиться, что в ходе сложного вычисления я не получил ложный результат из-за недостаточной точности или аномалий округления?
О. Десятичный модуль упрощает проверку результатов. Рекомендуется повторно выполнить вычисления, используя более высокую точность и различные режимы округления. Значительные различия в результатах указывают на недостаточную точность, проблемы с режимом округления, некорректные входные данные или численно неустойчивый алгоритм.
В. Я заметил, что контекстная точность применяется к результатам операций, но не к входным данным. Есть ли что-то, на что следует обратить внимание при смешивании значений разной точности
О. Да. Принцип заключается в том, что все значения считаются точными, как и арифметика для этих значений. Округляются только результаты. Преимущество ввода в том, что «что вы вводите, то и получаете». Недостатком является то, что результаты могут выглядеть странно, если вы забудете, что входные данные не были округлены:
>>> getcontext().prec = 3
>>> Decimal('3.104') + Decimal('2.104')
Decimal('5.21')
>>> Decimal('3.104') + Decimal('0.000') + Decimal('2.104')
Decimal('5.20')
Решение заключается либо в повышении точности, либо в принудительном округлении входных данных с помощью операции «унарный плюс»:
>>> getcontext().prec = 3
>>> +Decimal('1.23456789') # unary plus triggers rounding
Decimal('1.23')
В качестве альтернативы, входные данные могут быть округлены при создании с использованием метода Context.create_decimal()
:
>>> Context(prec=5, rounding=ROUND_DOWN).create_decimal('1.2345678')
Decimal('1.2345')
Вопрос: Быстра ли реализация CPython для больших чисел
Ответ: Да. В реализациях CPython и PyPy3 версии модуля decimal для CCF FI интегрируют высокоскоростную библиотеку libmpdec для арифметики с плавающей запятой произвольной точности с правильным округлением в десятичной системе счисления [1]. libmpdec
использует Karatsuba multiplication для вычислений среднего размера. числа и Number Theoretic Transform для очень больших чисел.
Контекст должен быть адаптирован для точной арифметики произвольной точности. Emin
и Emax
всегда должны быть установлены на максимальные значения, clamp
всегда должно быть равно 0 (по умолчанию). Установка prec
требует некоторой осторожности.
Самый простой способ опробовать арифметику bignum - это использовать максимальное значение для prec
, а также [2]:
>>> setcontext(Context(prec=MAX_PREC, Emax=MAX_EMAX, Emin=MIN_EMIN))
>>> x = Decimal(2) ** 256
>>> x / 128
Decimal('904625697166532776746648320380374280103671755200316906558262375061821325312')
Для получения неточных результатов значение MAX_PREC
слишком велико на 64-разрядных платформах, и доступной памяти будет недостаточно:
>>> Decimal(1) / 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
MemoryError
В системах с избыточным распределением (например, Linux) более сложным подходом является настройка prec
в зависимости от объема доступной оперативной памяти. Предположим, что у вас 8 ГБ оперативной памяти и ожидается, что 10 одновременных операндов будут использовать максимум 500 МБ каждый.:
>>> import sys
>>>
>>> # Maximum number of digits for a single operand using 500MB in 8-byte words
>>> # with 19 digits per word (4-byte and 9 digits for the 32-bit build):
>>> maxdigits = 19 * ((500 * 1024**2) // 8)
>>>
>>> # Check that this works:
>>> c = Context(prec=maxdigits, Emax=MAX_EMAX, Emin=MIN_EMIN)
>>> c.traps[Inexact] = True
>>> setcontext(c)
>>>
>>> # Fill the available precision with nines:
>>> x = Decimal(0).logical_invert() * 9
>>> sys.getsizeof(x)
524288112
>>> x + 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.Inexact: [<class 'decimal.Inexact'>]
В общем случае (и особенно в системах без избыточного распределения) рекомендуется оценивать еще более жесткие границы и устанавливать Inexact
, если ожидается, что все вычисления будут точными.