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
Added in version 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')
Некоторые математические функции также доступны в Decimal:
>>> getcontext().prec = 28
>>> Decimal(2).sqrt()
Decimal('1.414213562373095048801688724')
>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal('10').ln()
Decimal('2.302585092994045684017991455')
>>> Decimal('10').log10()
Decimal('1')
Метод quantize()
округляет число до фиксированной экспоненты. Этот метод полезен для монетарных приложений, в которых результаты часто округляются до фиксированного числа знаков:
>>> Decimal('7.325').quantize(Decimal('.01'), rounding=ROUND_DOWN)
Decimal('7.32')
>>> Decimal('7.325').quantize(Decimal('1.'), rounding=ROUND_UP)
Decimal('8')
Как показано выше, функция getcontext()
получает доступ к текущему контексту и позволяет изменить настройки. Такой подход отвечает потребностям большинства приложений.
Для более сложной работы может оказаться полезным создание альтернативных контекстов с помощью конструктора Context(). Чтобы сделать альтернативный контекст активным, используйте функцию setcontext()
.
В соответствии со стандартом, модуль decimal
предоставляет два готовых к использованию стандартных контекста, BasicContext
и ExtendedContext
. Первый особенно полезен для отладки, поскольку в нем включены многие ловушки:
>>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN)
>>> setcontext(myothercontext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857142857142857142857142857')
>>> ExtendedContext
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[], traps=[])
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857143')
>>> Decimal(42) / Decimal(0)
Decimal('Infinity')
>>> setcontext(BasicContext)
>>> Decimal(42) / Decimal(0)
Traceback (most recent call last):
File "<pyshell#143>", line 1, in -toplevel-
Decimal(42) / Decimal(0)
DivisionByZero: x / 0
Контексты также имеют сигнальные флаги для отслеживания исключительных условий, возникающих во время вычислений. Флаги остаются установленными до тех пор, пока не будут явно очищены, поэтому лучше всего очищать флаги перед каждым набором контролируемых вычислений с помощью метода clear_flags()
.
>>> setcontext(ExtendedContext)
>>> getcontext().clear_flags()
>>> Decimal(355) / Decimal(113)
Decimal('3.14159292')
>>> getcontext()
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])
Запись flags показывает, что рациональное приближение к пи было округлено (цифры за пределами точности контекста были отброшены) и что результат неточный (некоторые из отброшенных цифр были ненулевыми).
Отдельные ловушки устанавливаются с помощью словаря в атрибуте traps
контекста:
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(0)
Decimal('Infinity')
>>> getcontext().traps[DivisionByZero] = 1
>>> Decimal(1) / Decimal(0)
Traceback (most recent call last):
File "<pyshell#112>", line 1, in -toplevel-
Decimal(1) / Decimal(0)
DivisionByZero: x / 0
Большинство программ изменяют текущий контекст только один раз, в начале программы. И во многих приложениях данные преобразуются в Decimal
с помощью единственного броска внутри цикла. Когда контекст установлен и десятичные числа созданы, основная часть программы манипулирует данными не иначе, чем с другими числовыми типами Python.
Десятичные объекты¶
- class decimal.Decimal(value='0', context=None)¶
Создайте новый объект
Decimal
на основе значения.Значение может быть целым числом, строкой, кортежем,
float
или другим объектомDecimal
. Если значение value не задано, возвращается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 при NaN.
Added in version 3.6.
- as_tuple()¶
Возвращает представление named tuple числа:
DecimalTuple(sign, digits, exponent)
.
- canonical()¶
Возвращает каноническую кодировку аргумента. В настоящее время кодировка экземпляра
Decimal
всегда каноническая, поэтому эта операция возвращает аргумент без изменений.
- compare(other, context=None)¶
Сравнивает значения двух экземпляров Decimal.
compare()
возвращает экземпляр Decimal, а если один из операндов - NaN, то результатом будет NaN:a or b is a NaN ==> Decimal('NaN') a < b ==> Decimal('-1') a == b ==> Decimal('0') a > b ==> Decimal('1')
- compare_signal(other, context=None)¶
Эта операция идентична методу
compare()
, за исключением того, что все NaN сигнализируют. То есть если ни один из операндов не является сигнальным NaN, то любой тихий операнд NaN рассматривается так, как если бы он был сигнальным NaN.
- compare_total(other, context=None)¶
Сравните два операнда, используя их абстрактное представление, а не числовое значение. Аналогично методу
compare()
, но результат дает общее упорядочивание для экземпляровDecimal
. Два экземпляраDecimal
с одинаковым числовым значением, но разными представлениями, при таком упорядочивании сравниваются неравнозначно:>>> Decimal('12.0').compare_total(Decimal('12')) Decimal('-1')
Тихие и сигнальные NaN также включаются в общий порядок. Результатом этой функции является
Decimal('0')
, если оба операнда имеют одинаковое представление,Decimal('-1')
, если первый операнд ниже в общем порядке, чем второй, иDecimal('1')
, если первый операнд выше в общем порядке, чем второй операнд. Подробнее об общем порядке см. в спецификации.Эта операция не зависит от контекста и является тихой: никакие флаги не изменяются и округление не выполняется. В качестве исключения версия на языке C может выдать ошибку InvalidOperation, если второй операнд не может быть точно преобразован.
- compare_total_mag(other, context=None)¶
Сравните два операнда, используя их абстрактное представление, а не их значение, как в
compare_total()
, но не обращая внимания на знак каждого операнда.x.compare_total_mag(y)
эквивалентенx.copy_abs().compare_total(y.copy_abs())
.Эта операция не зависит от контекста и является тихой: никакие флаги не изменяются и округление не выполняется. В качестве исключения версия на языке C может выдать ошибку InvalidOperation, если второй операнд не может быть точно преобразован.
- conjugate()¶
Просто возвращает self, этот метод предназначен только для соответствия спецификации Decimal.
- copy_abs()¶
Возвращает абсолютное значение аргумента. Эта операция не зависит от контекста и является тихой: никакие флаги не изменяются и округление не выполняется.
- copy_negate()¶
Возвращает отрицание аргумента. Эта операция не зависит от контекста и является тихой: никакие флаги не изменяются и округление не выполняется.
- copy_sign(other, context=None)¶
Возвращает копию первого операнда со знаком, равным знаку второго операнда. Например:
>>> Decimal('2.3').copy_sign(Decimal('-1.5')) Decimal('-2.3')
Эта операция не зависит от контекста и является тихой: никакие флаги не изменяются и округление не выполняется. В качестве исключения версия на языке C может выдать ошибку InvalidOperation, если второй операнд не может быть точно преобразован.
- exp(context=None)¶
Возвращает значение (натуральной) экспоненциальной функции
e**x
при заданном числе. Результат корректно округляется с использованием режима округленияROUND_HALF_EVEN
.>>> Decimal(1).exp() Decimal('2.718281828459045235360287471') >>> Decimal(321).exp() Decimal('2.561702493119680037517373933E+139')
- classmethod from_float(f)¶
Альтернативный конструктор, принимающий только экземпляры
float
илиint
.Обратите внимание, что
Decimal.from_float(0.1)
- это не то же самое, чтоDecimal('0.1')
. Поскольку 0.1 не является точным представлением в двоичной системе с плавающей запятой, значение сохраняется как ближайшее представляемое значение, которым является0x1.999999999999ap-4
. Эквивалентное значение в десятичной системе счисления -0.1000000000000000055511151231257827021181583404541015625
.Примечание
Начиная с Python 3.2, экземпляр
Decimal
также может быть создан непосредственно изfloat
.>>> Decimal.from_float(0.1) Decimal('0.1000000000000000055511151231257827021181583404541015625') >>> Decimal.from_float(float('nan')) Decimal('NaN') >>> Decimal.from_float(float('inf')) Decimal('Infinity') >>> Decimal.from_float(float('-inf')) Decimal('-Infinity')
Added in version 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)¶
Используется для получения канонических значений класса эквивалентности в текущем или указанном контексте.
Семантика этой операции такая же, как и унарной операции плюс, за исключением того, что если конечный результат конечен, то он приводится к простейшей форме с удалением всех нулей в конце и сохранением знака. То есть если коэффициент ненулевой и кратен десяти, то коэффициент делится на десять и экспонента увеличивается на 1. В противном случае (коэффициент нулевой) экспонента устанавливается в 0. Во всех случаях знак не изменяется.
Например,
Decimal('32.100')
иDecimal('0.321000e+2')
нормализуются к эквивалентному значениюDecimal('32.1')
.Обратите внимание, что округление применяется до приведения к простейшему виду.
В последних версиях спецификации эта операция также известна как
reduce
.
- number_class(context=None)¶
Возвращает строку, описывающую класс операнда. Возвращаемое значение - одна из следующих десяти строк.
"-Infinity"
, указывая на то, что операнд - отрицательная бесконечность."-Normal"
, что указывает на то, что операнд является отрицательным нормальным числом."-Subnormal"
, указывая на то, что операнд отрицательный и субнормальный."-Zero"
, указывая, что операнд - отрицательный ноль."+Zero"
, указывая, что операнд - положительный ноль."+Subnormal"
, указывая на то, что операнд положительный и субнормальный."+Normal"
, что указывает на то, что операнд является положительным нормальным числом."+Infinity"
, указывая на то, что операнд - положительная бесконечность."NaN"
, что указывает на то, что операнд является тихим NaN (Not a Number)."sNaN"
, указывая на то, что операнд является сигнальным NaN.
- quantize(exp, rounding=None, context=None)¶
Возвращает значение, равное первому операнду после округления и с экспонентой второго операнда.
>>> Decimal('1.41421356').quantize(Decimal('1.000')) Decimal('1.414')
В отличие от других операций, если длина коэффициента после операции квантования будет больше точности, то подается сигнал
InvalidOperation
. Это гарантирует, что, если не возникнет ошибки, квантованная экспонента всегда будет равна экспоненте правого операнда.Также, в отличие от других операций, квантование никогда не подает сигнал Underflow, даже если результат субнормальный и неточный.
Если экспонента второго операнда больше экспоненты первого, то может потребоваться округление. В этом случае режим округления определяется аргументом
rounding
, если он задан, иначе - заданным аргументомcontext
; если ни один из аргументов не задан, то используется режим округления контекста текущего потока.Ошибка возвращается, если полученная экспонента больше
Emax
или меньшеEtiny()
.
- radix()¶
Возвращает
Decimal(10)
, радикс (основание), в котором классDecimal
выполняет все свои арифметические действия. Включено для совместимости со спецификацией.
- remainder_near(other, context=None)¶
Возвращает остаток от деления себя на другого. Это отличается от
self % other
тем, что знак остатка выбирается таким образом, чтобы минимизировать его абсолютное значение. Точнее, возвращаемое значение равноself - n * other
, гдеn
- целое число, ближайшее к точному значениюself / other
, а если два целых числа одинаково близки, то выбирается четное.Если результат равен нулю, то его знак будет равен знаку self.
>>> Decimal(18).remainder_near(Decimal(10)) Decimal('-2') >>> Decimal(25).remainder_near(Decimal(10)) Decimal('5') >>> Decimal(35).remainder_near(Decimal(10)) Decimal('-5')
- rotate(other, context=None)¶
Возвращает результат поворота цифр первого операнда на величину, заданную вторым операндом. Второй операнд должен быть целым числом в диапазоне от -прецизионности до -прецизионности. Абсолютное значение второго операнда дает количество мест для поворота. Если второй операнд положительный, то поворот осуществляется влево, в противном случае - вправо. Коэффициент первого операнда при необходимости дополняется слева нулями с точностью до длины. Знак и экспонента первого операнда не изменяются.
- same_quantum(other, context=None)¶
Проверьте, имеют ли self и other одинаковую экспоненту или оба равны
NaN
.Эта операция не зависит от контекста и является тихой: никакие флаги не изменяются и округление не выполняется. В качестве исключения версия на языке C может выдать ошибку InvalidOperation, если второй операнд не может быть точно преобразован.
- scaleb(other, context=None)¶
Возвращает первый операнд с экспонентой, скорректированной на второй. Эквивалентно, возвращается первый операнд, умноженный на
10**other
. Второй операнд должен быть целым числом.
- shift(other, context=None)¶
Возвращает результат сдвига цифр первого операнда на величину, заданную вторым операндом. Второй операнд должен быть целым числом в диапазоне -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, **kwargs)¶
Возвращает менеджер контекста, который установит текущий контекст для активного потока в копию ctx при входе в with-выражение и восстановит предыдущий контекст при выходе из with-выражения. Если контекст не указан, используется копия текущего контекста. Аргумент kwargs используется для установки атрибутов нового контекста.
Например, следующий код устанавливает текущую десятичную точность в 42 знака, выполняет вычисление, а затем автоматически восстанавливает предыдущий контекст:
from decimal import localcontext with localcontext() as ctx: ctx.prec = 42 # Perform a high precision calculation s = calculate_something() s = +s # Round the final result back to the default precision
Если использовать аргументы в виде ключевых слов, то код будет выглядеть следующим образом:
from decimal import localcontext with localcontext(prec=42) as ctx: s = calculate_something() s = +s
Вызывает
TypeError
, если kwargs предоставляет атрибут, которыйContext
не поддерживает. ВызываетTypeError
илиValueError
, если kwargs предоставил недопустимое значение для атрибута.Изменено в версии 3.11:
localcontext()
теперь поддерживает установку атрибутов контекста с помощью аргументов ключевых слов.
Новые контексты также могут быть созданы с помощью конструктора Context
, описанного ниже. Кроме того, модуль предоставляет три готовых контекста:
- class decimal.BasicContext¶
Это стандартный контекст, определенный спецификацией General Decimal Arithmetic Specification. Точность установлена на девять. Округление установлено в
ROUND_HALF_UP
. Все флаги очищены. Разрешены все ловушки (рассматриваются как исключения), кромеInexact
,Rounded
иSubnormal
.Поскольку многие ловушки включены, этот контекст полезен для отладки.
- class decimal.ExtendedContext¶
Это стандартный контекст, определенный спецификацией General Decimal Arithmetic Specification. Точность установлена на девять. Округление установлено в
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')
Значение 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
.Added in version 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
Added in version 3.1.
- Etiny()¶
Возвращает значение, равное
Emin - prec + 1
, которое является минимальным значением экспоненты для субнормальных результатов. Если происходит переполнение, экспонента устанавливается вEtiny
.
- Etop()¶
Возвращает значение, равное
Emax - prec + 1
.
Обычный подход к работе с десятичными числами заключается в создании экземпляров
Decimal
и последующем применении арифметических операций, которые происходят в рамках текущего контекста активного потока. Альтернативный подход заключается в использовании контекстных методов для вычислений в рамках определенного контекста. Эти методы аналогичны методам для классаDecimal
и лишь кратко описаны здесь.- abs(x)¶
Возвращает абсолютное значение x.
- add(x, y)¶
Возвращает сумму x и y.
- canonical(x)¶
Возвращает тот же объект Decimal x.
- compare(x, y)¶
Сравнивает x и y численно.
- compare_signal(x, y)¶
Сравнивает значения двух операндов численно.
- compare_total(x, y)¶
Сравнивает два операнда, используя их абстрактное представление.
- compare_total_mag(x, y)¶
Сравнивает два операнда, используя их абстрактное представление, игнорируя знак.
- copy_abs(x)¶
Возвращает копию x со знаком, установленным в 0.
- copy_negate(x)¶
Возвращает копию x с инвертированным знаком.
- copy_sign(x, y)¶
Копирует знак из y в x.
- divide(x, y)¶
Верните x, деленное на y.
- divide_int(x, y)¶
Возвращает x, деленное на y, усеченное до целого числа.
- divmod(x, y)¶
Делит два числа и возвращает целую часть результата.
- exp(x)¶
Возвращает
e ** x
.
- fma(x, y, z)¶
Возвращает x, умноженное на y, плюс z.
- is_canonical(x)¶
Возвращает
True
, если x является каноническим; в противном случае возвращаетFalse
.
- is_finite(x)¶
Возвращает
True
, если x конечен; в противном случае возвращаетFalse
.
- is_infinite(x)¶
Возвращает
True
, если x бесконечно; в противном случае возвращаетFalse
.
- is_nan(x)¶
Возвращает
True
, если x является qNaN или sNaN; в противном случае возвращаетFalse
.
- is_normal(x)¶
Возвращает
True
, если x - обычное число; в противном случае возвращаетFalse
.
- is_qnan(x)¶
Возвращает
True
, если x - тихий NaN; в противном случае возвращаетFalse
.
- is_signed(x)¶
Возвращает
True
, если x отрицательно; в противном случае возвращаетFalse
.
- is_snan(x)¶
Возвращает
True
, если x - сигнальный NaN; в противном случае возвращаетFalse
.
- is_subnormal(x)¶
Возвращает
True
, если x является субнормальным; в противном случае возвращаетFalse
.
- is_zero(x)¶
Возвращает
True
, если x - ноль; в противном случае возвращаетFalse
.
- ln(x)¶
Возвращает натуральный (основание e) логарифм от x.
- log10(x)¶
Возвращает логарифм по основанию 10 от x.
- logb(x)¶
Возвращает экспоненту величины MSD операнда.
- logical_and(x, y)¶
Применяет логическую операцию and между цифрами каждого операнда.
- logical_invert(x)¶
Инвертируйте все цифры в x.
- logical_or(x, y)¶
Применяет логическую операцию or между цифрами каждого операнда.
- logical_xor(x, y)¶
Применяет логическую операцию xor между цифрами каждого операнда.
- max(x, y)¶
Сравнивает два значения в числовом выражении и возвращает максимальное.
- max_mag(x, y)¶
Сравнивает значения численно, игнорируя их знак.
- min(x, y)¶
Сравнивает два значения численно и возвращает минимальное.
- min_mag(x, y)¶
Сравнивает значения численно, игнорируя их знак.
- minus(x)¶
Минус соответствует унарному префиксному оператору минус в Python.
- multiply(x, y)¶
Возвращает произведение x и y.
- next_minus(x)¶
Возвращает наибольшее представимое число, меньшее, чем x.
- next_plus(x)¶
Возвращает наименьшее представимое число, большее, чем x.
- next_toward(x, y)¶
Возвращает число, ближайшее к x, в направлении к y.
- normalize(x)¶
Уменьшает x до его простейшей формы.
- number_class(x)¶
Возвращает указание на класс x.
- plus(x)¶
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
. Это немного быстрее в некоторых сценариях с вложенным контекстом.Added in version 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; в противном случае округлите в сторону нуля.
Сигналы¶
Сигналы представляют собой условия, возникающие во время вычислений. Каждый из них соответствует одному контекстному флагу и одной контекстной ловушке.
Флаг контекста устанавливается всякий раз, когда встречается условие. После вычисления флаги могут быть проверены в информационных целях (например, чтобы определить, было ли вычисление точным). После проверки флагов не забудьте очистить все флаги перед началом следующего вычисления.
Если для сигнала установлена ловушка контекста, то условие вызывает возбуждение исключения 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¶
Включите более строгую семантику для смешивания float и Decimals.
Если сигнал не захвачен (по умолчанию), смешивание плавающих и десятичных чисел разрешено в конструкторе
Decimal
,create_decimal()
и во всех операторах сравнения. И преобразование, и сравнение являются точными. Любое появление смешанной операции молча фиксируется установкойFloatOperation
в контекстных флагах. Явные преобразования сfrom_float()
илиcreate_decimal_from_float()
не устанавливают флаг.В противном случае (сигнал задерживается) молчат только сравнения равенств и явные преобразования. Все остальные смешанные операции вызывают сигнал
FloatOperation
.
В следующей таблице представлена иерархия сигналов:
exceptions.ArithmeticError(exceptions.Exception)
DecimalException
Clamped
DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
Inexact
Overflow(Inexact, Rounded)
Underflow(Inexact, Rounded, Subnormal)
InvalidOperation
Rounded
Subnormal
FloatOperation(DecimalException, exceptions.TypeError)
Заметки о плавающей точке¶
Устранение ошибок округления с повышением точности¶
Использование десятичной плавающей точки устраняет ошибку десятичного представления (позволяя точно представить 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. Это происходит после вычисления. Философия десятичной спецификации заключается в том, что числа считаются точными и создаются независимо от текущего контекста. Они даже могут иметь большую точность, чем текущий контекст. Вычисления выполняются с этими точными входными данными, а затем округление (или другие контекстные операции) применяется к результату вычислений:
>>> 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')
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-версии десятичного модуля интегрирована высокоскоростная библиотека 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'>]
В общем случае (и особенно в системах без overallocation) рекомендуется оценивать еще более жесткие границы и устанавливать ловушку Inexact
, если ожидается, что все вычисления будут точными.