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')
И двоичная, и десятичная плавающая точка реализованы в терминах опубликованных стандартов. В то время как встроенный тип float раскрывает лишь скромную часть своих возможностей, модуль 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')
. Если значение является строкой, оно должно соответствовать синтаксису десятичной числовой строки после удаления ведущих и последующих пробельных символов, а также знаков подчеркивания: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')
.Точность контекста не влияет на то, сколько цифр будет храниться. Это определяется исключительно количеством цифр в значении. Например,
Decimal('3.00000')
записывает все пять нулей, даже если точность контекста равна только трем.Цель аргумента context - определить, что делать, если value - неправильно сформированная строка. Если контекст ловит
InvalidOperation
, возникает исключение; в противном случае конструктор возвращает новый Decimal со значением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()
возвращает 7. Используется для определения положения старшей цифры по отношению к десятичной точке.
-
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)¶ Сравнивает значения двух экземпляров Decimal.
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 может выдать ошибку 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 Specification.
-
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)¶ Сложенное умножение-добавление. Возвращает self*other+third без округления промежуточного продукта self*other.
>>> Decimal(2).fma(3, 5) Decimal('11')
-
is_canonical
()¶ Возвращает
True
, если аргумент канонический, иFalse
в противном случае. В настоящее время экземплярDecimal
всегда канонический, поэтому эта операция всегда возвращаетTrue
.
-
is_finite
()¶ Возвращает
True
, если аргумент - конечное число, иFalse
, если аргумент - бесконечность или NaN.
-
is_infinite
()¶ Возвращает
True
, если аргумент является положительной или отрицательной бесконечностью, иFalse
в противном случае.
-
is_nan
()¶ Возвращает
True
, если аргумент является (тихим или сигнальным) NaN иFalse
в противном случае.
-
is_normal
(context=None)¶ Возвращает
True
, если аргумент является нормальным конечным числом. ВозвращаетFalse
, если аргумент нулевой, субнормальный, бесконечный или NaN.
-
is_signed
()¶ Возвращает
True
, если аргумент имеет отрицательный знак, иFalse
в противном случае. Обратите внимание, что нули и NaN могут нести знаки.
-
is_subnormal
(context=None)¶ Возвращает
True
, если аргумент субнормальный, иFalse
в противном случае.
-
is_zero
()¶ Возвращает
True
, если аргумент является (положительным или отрицательным) нулем, иFalse
в противном случае.
-
ln
(context=None)¶ Возвращает натуральный (основание e) логарифм операнда. Результат корректно округляется с использованием режима округления
ROUND_HALF_EVEN
.
-
log10
(context=None)¶ Возвращает логарифм операнда по основанию десять. Результат правильно округляется с использованием режима округления
ROUND_HALF_EVEN
.
-
logb
(context=None)¶ Для ненулевого числа возвращает скорректированную экспоненту своего операнда в виде экземпляра
Decimal
. Если операнд равен нулю, то возвращаетсяDecimal('-Infinity')
и устанавливается флагDivisionByZero
. Если операндом является бесконечность, то возвращаетсяDecimal('Infinity')
.
-
logical_and
(other, context=None)¶ logical_and()
- это логическая операция, которая принимает два логических операнда (см. Логические операнды). Результатом является поразрядное отношениеand
двух операндов.
-
logical_invert
(context=None)¶ logical_invert()
- это логическая операция. Результатом является поразрядная инверсия операнда.
-
logical_or
(other, context=None)¶ logical_or()
- это логическая операция, которая принимает два логических операнда (см. Логические операнды). Результатом является поразрядное отношениеor
двух операндов.
-
logical_xor
(other, context=None)¶ logical_xor()
- это логическая операция, которая принимает два логических операнда (см. Логические операнды). Результатом является поразрядное исключающее или из двух операндов.
-
max
(other, context=None)¶ Подобно
max(self, other)
за исключением того, что перед возвратом применяется правило контекстного округления, а значенияNaN
либо сигнализируются, либо игнорируются (в зависимости от контекста и того, являются ли они сигнальными или тихими).
-
max_mag
(other, context=None)¶ Аналогичен методу
max()
, но сравнение производится по абсолютным значениям операндов.
-
min
(other, context=None)¶ Подобно
min(self, other)
за исключением того, что перед возвратом применяется правило контекстного округления, а значенияNaN
либо сигнализируются, либо игнорируются (в зависимости от контекста и того, являются ли они сигнальными или тихими).
-
min_mag
(other, context=None)¶ Аналогичен методу
min()
, но сравнение производится по абсолютным значениям операндов.
-
next_minus
(context=None)¶ Возвращает наибольшее число, представимое в заданном контексте (или в контексте текущего потока, если контекст не задан), которое меньше заданного операнда.
-
next_plus
(context=None)¶ Возвращает наименьшее число, представимое в заданном контексте (или в контексте текущего потока, если контекст не задан), которое больше заданного операнда.
-
next_toward
(other, context=None)¶ Если оба операнда неравны, возвращается число, ближайшее к первому операнду в направлении второго операнда. Если оба операнда численно равны, возвращается копия первого операнда со знаком, равным знаку второго операнда.
-
normalize
(context=None)¶ Нормализуйте число, удалив самые правые нули и преобразовав любой результат, равный
Decimal('0')
, вDecimal('0e0')
. Используется для получения канонических значений для атрибутов класса эквивалентности. Например,Decimal('32.100')
иDecimal('0.321000e+2')
оба нормализуются до эквивалентного значенияDecimal('32.1')
.
-
number_class
(context=None)¶ Возвращает строку, описывающую класс операнда. Возвращаемое значение является одной из следующих десяти строк.
"-Infinity"
, указывая на то, что операнд является отрицательной бесконечностью."-Normal"
, указывая, что операнд является отрицательным нормальным числом."-Subnormal"
, указывая на то, что операнд отрицательный и субнормальный."-Zero"
, указывая, что операнд является отрицательным нулем."+Zero"
, указывая, что операнд является положительным нулем."+Subnormal"
, указывая на то, что операнд положительный и субнормальный."+Normal"
, указывая, что операнд является положительным нормальным числом."+Infinity"
, указывая на то, что операнд - положительная бесконечность."NaN"
, указывая, что операнд является тихим NaN (Not a Number)."sNaN"
, указывая, что операнд является сигнальным NaN.
-
quantize
(exp, rounding=None, context=None)¶ Возвращает значение, равное первому операнду после округления и с экспонентой второго операнда.
>>> Decimal('1.41421356').quantize(Decimal('1.000')) Decimal('1.414')
В отличие от других операций, если длина коэффициента после операции квантования будет больше точности, то подается сигнал
InvalidOperation
. Это гарантирует, что, если не возникнет ошибки, квантованная экспонента всегда будет равна экспоненте правого операнда.Также, в отличие от других операций, квантование никогда не подает сигнал Underflow, даже если результат является ненормальным и неточным.
Если экспонента второго операнда больше экспоненты первого, то может потребоваться округление. В этом случае режим округления определяется аргументом
rounding
, если он задан, иначе - заданным аргументомcontext
; если ни один из аргументов не задан, то используется режим округления контекста текущего потока.Ошибка возвращается, если полученная экспонента больше
Emax
или меньшеEtiny
.
-
radix
()¶ Возвращает
Decimal(10)
, радикс (основание), в котором классDecimal
выполняет всю свою арифметику. Включено для совместимости со спецификацией.
-
remainder_near
(other, context=None)¶ Возвращает остаток от деления self на other. Отличается от
self % other
тем, что знак остатка выбирается таким образом, чтобы минимизировать его абсолютное значение. Точнее, возвращаемое значение равноself - n * other
, гдеn
- целое число, ближайшее к точному значениюself / other
, а если два целых числа одинаково близки, то выбирается четное.Если результат равен нулю, то его знак будет знаком себя.
>>> Decimal(18).remainder_near(Decimal(10)) Decimal('-2') >>> Decimal(25).remainder_near(Decimal(10)) Decimal('5') >>> Decimal(35).remainder_near(Decimal(10)) Decimal('-5')
-
rotate
(other, context=None)¶ Возвращает результат поворота цифр первого операнда на величину, заданную вторым операндом. Второй операнд должен быть целым числом в диапазоне от -precision до precision. Абсолютное значение второго операнда дает количество мест для поворота. Если второй операнд положителен, то поворот осуществляется влево, в противном случае - вправо. Коэффициент первого операнда при необходимости дополняется слева нулями для увеличения точности длины. Знак и экспонента первого операнда остаются неизменными.
-
same_quantum
(other, context=None)¶ Проверьте, имеют ли self и other одинаковую экспоненту или оба они
NaN
.Эта операция не зависит от контекста и является тихой: не изменяются флаги и не выполняется округление. В качестве исключения версия на языке C может выдать ошибку InvalidOperation, если второй операнд не может быть точно преобразован.
-
scaleb
(other, context=None)¶ Возвращает первый операнд с экспонентой, скорректированной на второй. Эквивалентно, возвращает первый операнд, умноженный на
10**other
. Второй операнд должен быть целым числом.
-
shift
(other, context=None)¶ Возвращает результат сдвига цифр первого операнда на величину, заданную вторым операндом. Второй операнд должен быть целым числом в диапазоне от -precision до precision. Абсолютное значение второго операнда дает количество мест для сдвига. Если второй операнд положителен, то сдвиг осуществляется влево, в противном случае - вправо. Цифры, сдвинутые в коэффициент, являются нулями. Знак и экспонента первого операнда остаются неизменными.
-
sqrt
(context=None)¶ Возвращает квадратный корень из аргумента с полной точностью.
-
to_eng_string
(context=None)¶ Преобразовать в строку, используя инженерную нотацию, если требуется экспонента.
Инженерная нотация имеет экспоненту, кратную 3. Это может оставить до 3 цифр слева от десятичного разряда и может потребовать добавления одного или двух нулей.
Например, это преобразует
Decimal('123E+1')
вDecimal('1.23E+3')
.
-
to_integral
(rounding=None, context=None)¶ Идентичен методу
to_integral_value()
. Имяto_integral
было сохранено для совместимости со старыми версиями.
-
to_integral_exact
(rounding=None, context=None)¶ Округлить до ближайшего целого числа, сигнализируя
Inexact
илиRounded
в зависимости от ситуации, если происходит округление. Режим округления определяется параметромrounding
, если он задан, иначе - заданным параметромcontext
. Если ни один из параметров не задан, то используется режим округления текущего контекста.
-
Логические операнды¶
Методы logical_and()
, logical_invert()
, logical_or()
и logical_xor()
ожидают, что их аргументы будут логическими операндами. Логический операнд* - это экземпляр Decimal
, экспонента и знак которого равны нулю, а все цифры либо 0
, либо 1
.
Контекстные объекты¶
Контексты - это среда для арифметических операций. Они регулируют точность, устанавливают правила округления, определяют, какие сигналы рассматриваются как исключения, и ограничивают диапазон для экспоненты.
Каждый поток имеет свой собственный текущий контекст, доступ к которому или изменение которого осуществляется с помощью функций getcontext()
и setcontext()
:
-
decimal.
getcontext
()¶ Возвращает текущий контекст для активного потока.
-
decimal.
setcontext
(c)¶ Установите текущий контекст для активного потока на c.
Вы также можете использовать оператор with
и функцию localcontext()
для временного изменения активного контекста.
-
decimal.
localcontext
(ctx=None)¶ Возвращает менеджер контекста, который установит текущий контекст для активного потока в копию ctx при входе в with-выражение и восстановит предыдущий контекст при выходе из with-выражения. Если контекст не указан, используется копия текущего контекста.
Например, следующий код устанавливает текущую десятичную точность в 42 знака, выполняет вычисление, а затем автоматически восстанавливает предыдущий контекст:
from decimal import localcontext with localcontext() as ctx: ctx.prec = 42 # Perform a high precision calculation s = calculate_something() s = +s # Round the final result back to the default precision
Новые контексты также могут быть созданы с помощью конструктора Context
, описанного ниже. Кроме того, модуль предоставляет три готовых контекста:
-
class
decimal.
BasicContext
¶ Это стандартный контекст, определенный Спецификацией общей десятичной арифметики. Точность установлена на девять. Округление установлено на
ROUND_HALF_UP
. Все флаги очищены. Все ловушки разрешены (рассматриваются как исключения), кромеInexact
,Rounded
иSubnormal
.Поскольку многие ловушки включены, этот контекст полезен для отладки.
-
class
decimal.
ExtendedContext
¶ Это стандартный контекст, определенный Спецификацией общей десятичной арифметики. Точность установлена на девять. Округление установлено на
ROUND_HALF_EVEN
. Все флаги очищены. Ловушки не включены (чтобы исключения не возникали во время вычислений).Поскольку ловушки отключены, этот контекст полезен для приложений, которые предпочитают иметь значение результата
NaN
илиInfinity
вместо того, чтобы вызывать исключения. Это позволяет приложению завершить выполнение при наличии условий, которые в противном случае остановили бы программу.
-
class
decimal.
DefaultContext
¶ Этот контекст используется конструктором
Context
в качестве прототипа для новых контекстов. Изменение поля (например, точности) приводит к изменению значения по умолчанию для новых контекстов, создаваемых конструкторомContext
.Этот контекст наиболее полезен в многопоточных средах. Изменение одного из полей до запуска потоков имеет эффект установки общесистемных значений по умолчанию. Изменять поля после запуска потоков не рекомендуется, так как это потребует синхронизации потоков для предотвращения условий гонки.
В однопоточных средах предпочтительнее вообще не использовать этот контекст. Вместо этого просто создавайте контексты в явном виде, как описано ниже.
Значениями по умолчанию являются
prec
=28
,rounding
=ROUND_HALF_EVEN
, и включенные ловушки дляOverflow
,InvalidOperation
иDivisionByZero
.
В дополнение к трем поставляемым контекстам, новые контексты могут быть созданы с помощью конструктора Context
.
-
class
decimal.
Context
(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)¶ Создает новый контекст. Если поле не указано или равно
None
, значения по умолчанию копируются изDefaultContext
. Если поле flags не указано или равноNone
, все флаги очищаются.prec - это целое число в диапазоне [
1
,MAX_PREC
], которое задает точность арифметических операций в контексте.Параметр округление является одной из констант, перечисленных в разделе Rounding 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')
Значение clamp
1
обеспечивает совместимость с десятичными форматами обмена с фиксированной шириной, указанными в IEEE 754.Класс
Context
определяет несколько методов общего назначения, а также большое количество методов для выполнения арифметических действий непосредственно в заданном контексте. Кроме того, для каждого из описанных выше методовDecimal
(за исключением методовadjusted()
иas_tuple()
) существует соответствующий методContext
. Например, дляContext
экземпляраC
иDecimal
экземпляраx
,C.exp(x)
эквивалентенx.exp(context=C)
. Каждый методContext
принимает целое число Python (экземплярint
) везде, где принимается экземпляр Decimal.-
clear_flags
()¶ Сбрасывает все флаги на
0
.
-
clear_traps
()¶ Сбрасывает все ловушки на значение
0
.Добавлено в версии 3.3.
-
copy
()¶ Возвращает дубликат контекста.
-
copy_decimal
(num)¶ Возвращает копию десятичного экземпляра 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')
Этот метод реализует операцию to-number спецификации IBM. Если аргумент является строкой, не допускаются пробелы и подчеркивания.
-
create_decimal_from_float
(f)¶ Создает новый экземпляр Decimal из float 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)¶ Применяет логическую операцию or между цифрами каждого операнда.
-
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
не является интегралом, а результат конечен и может быть выражен точно в „точных“ цифрах. Используется режим округления контекста. В версии для 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 используется контекст thread-local, а не coroutine-local, и значение равноFalse
. Это немного быстрее в некоторых сценариях с вложенными контекстами.
Добавлено в версии 3.9: перенесен в версии 3.7 и 3.8.
Режимы округления¶
-
decimal.
ROUND_CEILING
¶ Круг в направлении
Infinity
.
-
decimal.
ROUND_DOWN
¶ Округляйте в сторону нуля.
-
decimal.
ROUND_FLOOR
¶ Круг в направлении
-Infinity
.
-
decimal.
ROUND_HALF_DOWN
¶ Округляйте до ближайшего, при этом количество неравенств стремится к нулю.
-
decimal.
ROUND_HALF_EVEN
¶ Округляйте до ближайшего, при равенстве переходите к ближайшему четному целому числу.
-
decimal.
ROUND_HALF_UP
¶ Округляйте до ближайшего значения, при этом от нуля отнимаются ничьи.
-
decimal.
ROUND_UP
¶ Округляйте от нуля.
-
decimal.
ROUND_05UP
¶ Округлите от нуля, если последняя цифра после округления в сторону нуля была бы 0 или 5; в противном случае округлите в сторону нуля.
Сигналы¶
Сигналы представляют условия, возникающие во время вычислений. Каждый из них соответствует одному контекстному флагу и одной контекстной ловушке.
Контекстный флаг устанавливается всякий раз, когда встречается условие. После вычисления флаги могут быть проверены в информационных целях (например, чтобы определить, было ли вычисление точным). После проверки флагов не забудьте очистить все флаги перед началом следующего вычисления.
Если для сигнала установлена ловушка контекста, то условие приводит к возникновению исключения Python. Например, если установлена ловушка DivisionByZero
, то при возникновении условия будет вызвано исключение DivisionByZero
.
-
class
decimal.
Clamped
¶ Изменил экспоненту для соответствия ограничениям представления.
Как правило, зажим происходит, когда экспонента выходит за пределы контекста
Emin
иEmax
. Если возможно, экспонента уменьшается до подходящего значения путем добавления нулей к коэффициенту.
-
class
decimal.
DecimalException
¶ Базовый класс для других сигналов и подкласс
ArithmeticError
.
-
class
decimal.
DivisionByZero
¶ Сигнализирует о делении не бесконечного числа на ноль.
Может возникать при делении, делении по модулю или при возведении числа в отрицательную степень. Если этот сигнал не пойман, возвращается
Infinity
или-Infinity
со знаком, определяемым входами вычисления.
-
class
decimal.
Inexact
¶ Указывает на то, что произошло округление, и результат не является точным.
Сигнализирует, когда ненулевые цифры были отброшены при округлении. Возвращается округленный результат. Флаг сигнала или ловушка используются для обнаружения неточных результатов.
-
class
decimal.
InvalidOperation
¶ Была выполнена недопустимая операция.
Указывает, что была запрошена операция, которая не имеет смысла. Если не поймана, возвращается
NaN
. Возможные причины включают:Infinity - Infinity 0 * Infinity Infinity / Infinity x % 0 Infinity % x sqrt(-x) and x > 0 0 ** 0 x ** (non-integer) x ** Infinity
-
class
decimal.
Overflow
¶ Численное переполнение.
Указывает, что экспонента больше, чем
Emax
после округления. Если ловушка не установлена, результат зависит от режима округления: либо округление внутрь до наибольшего представимого конечного числа, либо округление наружу доInfinity
. В любом случае,Inexact
иRounded
также сигнализируются.
-
class
decimal.
Rounded
¶ Округление произошло, хотя, возможно, информация не была потеряна.
Сигнализируется всякий раз, когда округление отбрасывает цифры; даже если эти цифры равны нулю (например, округление
5.00
до5.0
). Если сигнал не пойман, результат возвращается без изменений. Этот сигнал используется для обнаружения потери значащих цифр.
-
class
decimal.
Subnormal
¶ Перед округлением экспонента была меньше
Emin
.Возникает, когда результат операции является ненормальным (экспонента слишком мала). Если ловушки нет, результат возвращается без изменений.
-
class
decimal.
Underflow
¶ Численное переполнение с округлением результата до нуля.
Возникает, когда субнормальный результат сдвигается к нулю в результате округления. Также сигнализируется
Inexact
иSubnormal
.
-
class
decimal.
FloatOperation
¶ Включите более строгую семантику для смешивания плавающих и десятичных чисел.
Если сигнал не заперт (по умолчанию), смешивание плавающих и десятичных чисел разрешено в конструкторе
Decimal
,create_decimal()
и во всех операторах сравнения. И преобразование, и сравнение являются точными. Любое появление смешанной операции молча фиксируется установкойFloatOperation
в контекстных флагах. Явные преобразования с помощьюfrom_float()
илиcreate_decimal_from_float()
не устанавливают флаг.В противном случае (сигнал задерживается), молчат только сравнения равенств и явные преобразования. Все остальные смешанные операции вызывают сигнал
FloatOperation
.
В следующей таблице представлена иерархия сигналов:
exceptions.ArithmeticError(exceptions.Exception)
DecimalException
Clamped
DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
Inexact
Overflow(Inexact, Rounded)
Underflow(Inexact, Rounded, Subnormal)
InvalidOperation
Rounded
Subnormal
FloatOperation(DecimalException, exceptions.TypeError)
Заметки о плавающей точке¶
Устранение ошибок округления с повышением точности¶
Использование десятичной плавающей точки устраняет ошибку десятичного представления (делая возможным точное представление 0.1
); однако при некоторых операциях все еще может возникать ошибка округления, когда ненулевые цифры превышают фиксированную точность.
Влияние ошибки округления может усиливаться при сложении или вычитании почти смещенных величин, что приводит к потере значимости. Кнут приводит два поучительных примера, когда округленная арифметика с плавающей запятой с недостаточной точностью приводит к нарушению ассоциативных и дистрибутивных свойств сложения:
# Examples from Seminumerical Algorithms, Section 4.2.2.
>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 8
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.5111111')
>>> u + (v + w)
Decimal('10')
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.01')
>>> u * (v+w)
Decimal('0.0060000')
Модуль decimal
позволяет восстановить тождества, расширив точность настолько, чтобы избежать потери значимости:
>>> getcontext().prec = 20
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.51111111')
>>> u + (v + w)
Decimal('9.51111111')
>>>
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.0060000')
>>> u * (v+w)
Decimal('0.0060000')
Особые значения¶
Система счисления для модуля decimal
предусматривает специальные значения, включая NaN
, sNaN
, -Infinity
, Infinity
и два нуля, +0
и -0
.
Бесконечности могут быть построены непосредственно с помощью: Decimal('Infinity')
. Также они могут возникать при делении на ноль, если сигнал DivisionByZero
не заперт. Аналогично, когда сигнал Overflow
не заперт, бесконечность может возникнуть в результате округления за пределы наибольшего представимого числа.
Бесконечности являются знаковыми (аффинными) и могут использоваться в арифметических операциях, где они рассматриваются как очень большие, неопределенные числа. Например, прибавление константы к бесконечности дает еще один бесконечный результат.
Некоторые операции являются неопределенными и возвращают NaN
, или, если сигнал InvalidOperation
пойман, вызывают исключение. Например, 0/0
возвращает NaN
, что означает «не число». Эта разновидность NaN
является тихой и, будучи созданной, будет проходить через другие вычисления, всегда приводя к другому NaN
. Такое поведение может быть полезно для серии вычислений, в которых иногда отсутствуют входные данные — оно позволяет продолжить вычисления, отмечая при этом определенные результаты как недопустимые.
Вариантом является sNaN
, который подает сигнал, а не молчит после каждой операции. Это полезное возвращаемое значение, когда недопустимый результат должен прервать вычисления для специальной обработки.
Поведение операторов сравнения Python может быть немного удивительным, если в них участвует NaN
. Проверка на равенство, когда одним из операндов является тихий или сигнальный NaN
, всегда возвращает False
(даже при выполнении Decimal('NaN')==Decimal('NaN')
), а проверка на неравенство всегда возвращает True
. Попытка сравнения двух десятичных дробей с помощью любого из операторов <
, <=
, >
или >=
вызовет сигнал InvalidOperation
, если один из операндов является NaN
, и вернет False
, если этот сигнал не пойман. Обратите внимание, что спецификация General Decimal Arithmetic не определяет поведение прямых сравнений; эти правила для сравнений с участием 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
Вопросы и ответы по десятичной дроби¶
Q. Набирать decimal.Decimal('1234.5')
очень обременительно. Есть ли способ минимизировать ввод текста при использовании интерактивного интерпретатора?
A. Некоторые пользователи сокращают конструктор до одной буквы:
>>> D = decimal.Decimal
>>> D('1.23') + D('3.45')
Decimal('4.68')
Q. В приложении с фиксированной точкой и двумя десятичными знаками некоторые входные данные имеют много знаков и должны быть округлены. Другие не должны иметь лишних цифр и должны быть проверены. Какие методы следует использовать?
A. Метод 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
Q. Если у меня есть допустимые двухпозиционные входы, как мне сохранить этот инвариант во всем приложении?
A. Некоторые операции, такие как сложение, вычитание и умножение на целое число, автоматически сохраняют фиксированную точку. Другие операции, такие как деление и умножение на нецелое число, изменят количество десятичных знаков и должны сопровождаться шагом 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')
Q. Существует множество способов выразить одно и то же значение. Числа 200
, 200.000
, 2E2
и 02E+4
имеют одно и то же значение с различной точностью. Есть ли способ преобразовать их к одному узнаваемому каноническому значению?
A. Метод 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')]
Q. Некоторые десятичные значения всегда печатаются с экспоненциальной нотацией. Есть ли способ получить неэкспоненциальное представление?
A. Для некоторых значений экспоненциальная нотация является единственным способом выразить количество значимых мест в коэффициенте. Например, выражение 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')
Q. Есть ли способ преобразовать обычное число float в Decimal
?
A. Да, любое двоичное число с плавающей запятой может быть точно выражено в десятичной системе счисления, хотя для точного преобразования может потребоваться больше точности, чем подсказывает интуиция:
>>> Decimal(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875')
Q. Как я могу убедиться, что в сложном вычислении я не получил ложный результат из-за недостаточной точности или аномалий округления.
A. Модуль десятичной дроби позволяет легко проверить результаты. Лучшей практикой является повторное выполнение вычислений с большей точностью и с различными режимами округления. Сильно различающиеся результаты указывают на недостаточную точность, проблемы с режимом округления, плохо обусловленные входные данные или численно неустойчивый алгоритм.
Q. Я заметил, что контекстная точность применяется к результатам операций, но не к входным данным. Есть ли что-то, чего следует остерегаться при смешивании значений с разной точностью?
A. Да. Принцип заключается в том, что все значения считаются точными, как и арифметические действия с этими значениями. Только результаты округляются. Преимущество ввода заключается в том, что «что введешь, то и получишь». Недостатком является то, что результаты могут выглядеть странно, если вы забудете, что входные данные не были округлены:
>>> 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')
Q. Является ли реализация CPython быстрой для больших чисел?
A. Да. В реализациях CPython и PyPy3 версии C/CFFI модуля decimal интегрируют высокоскоростную библиотеку 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
В системах с overallocation (например, 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'>]
В общем случае (и особенно в системах без overallocation) рекомендуется оценивать еще более жесткие границы и устанавливать ловушку Inexact
, если ожидается, что все вычисления будут точными.