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