Содержание страницы
decimal – десятичная арифметика с фиксированной и плавающей запятой¶decimal – Decimal fixed-point and floating-point arithmetic
Исходный код: 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. Хотя он близок к нулю, эти различия препятствуют надёжной проверке на равенство и могут накапливаться. По этой причине десятичная арифметика предпочтительна в бухгалтерских приложениях, где существуют строгие инварианты равенства.Модуль 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, Общая спецификация десятичной арифметики.
Быстрый старт¶Quick-start Tutorial
Обычно работа с десятичными числами начинается с импорта модуля decimal, просмотра текущего
контекста с помощью 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 # Установить новую точность
Экземпляры 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-версии превышены, создание
decimal вызывает InvalidOperation:
>>> Decimal("1e9999999999999999999")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
Изменено в версии 3.3.
Decimal хорошо взаимодействует с большей частью остального 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¶Decimal objects
- 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для отрицательного),tupleцифр и целочисленный показатель степени. Например,Decimal((0, (1, 4, 1, 4), -3))возвращаетDecimal('1.414').Если value является
float, двоичное значение с плавающей запятой без потерь преобразуется в его точный десятичный эквивалент. Это преобразование часто может потребовать 53 или более цифр точности. Например,Decimal(float('1.1'))преобразуется вDecimal('1.100000000000000088817841970012523233890533447265625').Точность context не влияет на количество сохраняемых цифр. Оно определяется исключительно количеством цифр в value. Например,
Decimal('3.00000')сохраняет все пять нулей, даже если точность контекста равна всего трём.Назначение аргумента context – определять, что делать, если value является некорректной строкой. Если контекст перехватывает
InvalidOperation, возбуждается исключение; в противном случае конструктор возвращает новый Decimal со значениемNaN.После создания объекты
Decimalнеизменяемы.Изменено в версии 3.2: Теперь аргумент конструктора может быть
floatэкземпляром.Изменено в версии 3.3: Аргументы
floatвозбуждают исключение, еслиFloatOperationловушка установлена. По умолчанию ловушка выключена.Изменено в версии 3.6: Символы подчёркивания разрешены для группировки, как и в литералах целых чисел и чисел с плавающей запятой в коде.
Объекты десятичных чисел с плавающей запятой имеют много общих свойств с другими встроенными числовыми типами, такими как
floatиint. К ним применимы все обычные математические операции и специальные методы. Кроме того, десятичные объекты можно копировать, сериализовать (pickle), выводить на печать, использовать в качестве ключей словаря, элементов множества, сравнивать, сортировать и преобразовывать к другому типу (например,floatилиint).Существуют небольшие различия между арифметикой над объектами Decimal и арифметикой над целыми числами и числами с плавающей запятой. Когда оператор остатка
%применяется к объектам Decimal, знак результата совпадает со знаком dividend, а не со знаком делителя:>>> (-7) % 4 1 >>> Decimal(-7) % Decimal(4) Decimal('-3')
Оператор целочисленного деления
//ведёт себя аналогично: возвращает целую часть истинного частного (отсечение к нулю), а не его пол, чтобы сохранить обычное тождествоx == (x // y) * y + x % y:>>> -7 // 4 -2 >>> Decimal(-7) // Decimal(4) Decimal('-1')
Операторы
%и//реализуют операцииremainderиdivide-integer(соответственно), как описано в спецификации.Объекты Decimal в общем случае нельзя комбинировать с числами с плавающей запятой или экземплярами
fractions.Fractionв арифметических операциях: попытка добавитьDecimalкfloat, например, вызоветTypeError. Однако можно использовать операторы сравнения Python для сравнения экземпляраDecimalxс другим числомy. Это позволяет избежать путаницы при проверке равенства чисел разных типов.Изменено в версии 3.2: Сравнение между экземплярами
Decimalи другими числовыми типами теперь полностью поддерживается.В дополнение к стандартным числовым свойствам объекты десятичных чисел с плавающей запятой также имеют ряд специализированных методов:
- adjusted()¶
Возвращает скорректированный показатель степени после сдвига самых правых цифр коэффициента до тех пор, пока не останется только ведущая цифра:
Decimal('321e+5').adjusted()возвращает семь. Используется для определения положения самой значащей цифры относительно десятичной точки.
- as_integer_ratio()¶
Возвращает пару
(n, d)целых чисел, представляющих данный экземплярDecimalв виде дроби, в несократимом виде и с положительным знаменателем:>>> Decimal('-3.14').as_integer_ratio() (-157, 50)
Преобразование точное. Возбуждает OverflowError для бесконечностей и ValueError для NaN.
Добавлено в версии 3.6.
- as_tuple()¶
Возвращает именованный кортеж представление числа:
DecimalTuple(sign, digits, exponent).
- canonical()¶
Возвращает каноническую кодировку аргумента. В настоящее время кодировка экземпляра
Decimalвсегда канонична, поэтому эта операция возвращает свой аргумент без изменений.
- compare(other, context=None)¶
Сравнивает значения двух экземпляров Decimal.
compare()возвращает экземпляр Decimal; если хотя бы один операнд является NaN, результат также будет NaN:a or b is a NaN ==> Decimal('NaN') a < b ==> Decimal('-1') a == b ==> Decimal('0') a > b ==> Decimal('1')
- compare_signal(other, context=None)¶
Эта операция идентична методу
compare(), за исключением того, что все NaN сигнализируют. То есть, если ни один операнд не является сигнальным NaN, то любой тихий NaN обрабатывается так, как если бы он был сигнальным NaN.
- compare_total(other, context=None)¶
Сравнивает два операнда, используя их абстрактное представление, а не числовое значение. Аналогично методу
compare(), но результат задаёт полный порядок на экземплярахDecimal. Два экземпляраDecimalс одинаковым числовым значением, но разными представлениями, в этом порядке считаются неравными:>>> Decimal('12.0').compare_total(Decimal('12')) Decimal('-1')
Тихие и сигнальные NaN также включены в полный порядок. Результат этой функции равен
Decimal('0'), если оба операнда имеют одинаковое представление,Decimal('-1'), если первый операнд меньше второго в полном порядке, иDecimal('1'), если первый операнд больше второго. См. спецификацию для подробностей полного порядка.Эта операция не зависит от контекста и является тихой: никакие флаги не меняются и округление не выполняется. Исключение составляет C-версия, которая может возбудить InvalidOperation, если второй операнд невозможно точно преобразовать.
- compare_total_mag(other, context=None)¶
Сравнивает два операнда, используя их абстрактное представление, а не их значение, как в
compare_total(), но игнорируя знак каждого операнда.x.compare_total_mag(y)эквивалентноx.copy_abs().compare_total(y.copy_abs()).Эта операция не зависит от контекста и является тихой: никакие флаги не меняются и округление не выполняется. Исключение составляет C-версия, которая может возбудить InvalidOperation, если второй операнд невозможно точно преобразовать.
- conjugate()¶
Просто возвращает self; этот метод существует только для соответствия спецификации Decimal.
- copy_abs()¶
Возвращает абсолютное значение аргумента. Эта операция не зависит от контекста и является тихой: флаги не изменяются и округление не выполняется.
- copy_negate()¶
Возвращает отрицание аргумента. Эта операция не зависит от контекста и является тихой: флаги не изменяются и округление не выполняется.
- copy_sign(other, context=None)¶
Возвращает копию первого операнда со знаком, установленным таким же, как знак второго операнда. Например:
>>> Decimal('2.3').copy_sign(Decimal('-1.5')) Decimal('-2.3')
Эта операция не зависит от контекста и является тихой: никакие флаги не меняются и округление не выполняется. Исключение составляет C-версия, которая может возбудить InvalidOperation, если второй операнд невозможно точно преобразовать.
- exp(context=None)¶
Возвращает значение (натуральной) показательной функции
e**xдля заданного числа. Результат корректно округляется с использованием режима округленияROUND_HALF_EVEN.>>> Decimal(1).exp() Decimal('2.718281828459045235360287471') >>> Decimal(321).exp() Decimal('2.561702493119680037517373933E+139')
- classmethod from_float(f)¶
Альтернативный конструктор, принимающий только экземпляры
floatилиint.Обратите внимание:
Decimal.from_float(0.1)не то же самое, чтоDecimal('0.1'). Поскольку 0.1 не может быть точно представлен в двоичной арифметике с плавающей запятой, значение сохраняется как ближайшее представимое значение, равное0x1.999999999999ap-4. Эквивалентное значение в десятичной записи –0.1000000000000000055511151231257827021181583404541015625.>>> 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_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 (не числом)."sNaN"– указывает, что операнд является сигнализирующим NaN.
- quantize(exp, rounding=None, context=None)¶
Возвращает значение, равное первому операнду после округления и имеющее экспоненту второго операнда.
>>> Decimal('1.41421356').quantize(Decimal('1.000')) Decimal('1.414')
В отличие от других операций, если длина коэффициента после операции quantize превышает точность, то сигнализируется
InvalidOperation. Это гарантирует, что, за исключением ошибочных ситуаций, экспонента после квантования всегда равна экспоненте правого операнда.Также, в отличие от других операций, 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)¶
Возвращает результат вращения цифр первого операнда на величину, заданную вторым операндом. Второй операнд должен быть целым числом в диапазоне от -precision до precision. Абсолютное значение второго операнда задаёт количество позиций для вращения. Если второй операнд положителен, вращение выполняется влево; в противном случае вращение выполняется вправо. Коэффициент первого операнда при необходимости дополняется слева нулями до длины precision. Знак и экспонента первого операнда не изменяются.
- same_quantum(other, context=None)¶
Проверяет, имеют ли self и other одинаковую экспоненту или оба равны
NaN.Эта операция не зависит от контекста и является тихой: никакие флаги не меняются и округление не выполняется. Исключение составляет C-версия, которая может возбудить InvalidOperation, если второй операнд невозможно точно преобразовать.
- scaleb(other, context=None)¶
Возвращает первый операнд с экспонентой, скорректированной на второй операнд. Эквивалентно умножению первого операнда на
10**other. Второй операнд должен быть целым числом.
- shift(other, context=None)¶
Возвращает результат сдвига цифр первого операнда на величину, заданную вторым операндом. Второй операнд должен быть целым числом в диапазоне от -precision до precision. Абсолютное значение второго операнда задаёт количество позиций для сдвига. Если второй операнд положителен, сдвиг выполняется влево; в противном случае сдвиг выполняется вправо. Вдвигаемые в коэффициент цифры являются нулями. Знак и экспонента первого операнда не изменяются.
- sqrt(context=None)¶
Возвращает квадратный корень аргумента с полной точностью.
- to_eng_string(context=None)¶
Преобразует в строку, используя инженерную запись, если нужен показатель степени.
В инженерной записи показатель степени кратен трём. Из-за этого слева от десятичной запятой может оставаться до трёх цифр, и может потребоваться добавление одного или двух конечных нулей.
Например, это преобразует
Decimal('123E+1')вDecimal('1.23E+3').
- to_integral(rounding=None, context=None)¶
Идентичен методу
to_integral_value(). Имяto_integralсохранено для совместимости со старыми версиями.
- to_integral_exact(rounding=None, context=None)¶
Округляет до ближайшего целого, сигнализируя
InexactилиRoundedв зависимости от ситуации, если округление происходит. Режим округления определяется параметромrounding, если он передан, иначе переданнымcontext. Если ни один из параметров не передан, используется режим округления текущего контекста.
- to_integral_value(rounding=None, context=None)¶
Округляет до ближайшего целого без сигнализации
InexactилиRounded. Если передан, применяет rounding; в противном случае использует метод округления из предоставленного context или текущего контекста.
Десятичные числа можно округлять с помощью функции
round():- round(number)
- round(number, ndigits)
Если ndigits не указан или равен
None, возвращает ближайшееintк number, при округлении связей (ties) до четного, игнорируя режим округления контекстаDecimal. ВызываетOverflowError, если number – бесконечность, илиValueError, если это (тихий или сигнальный) NaN.Если ndigits является
int, учитывается режим округления контекста, и возвращаетсяDecimal, представляющий number, округлённый до ближайшего кратногоDecimal('1E-ndigits'); в этом случаеround(number, ndigits)эквивалентноself.quantize(Decimal('1E-ndigits')). ВозвращаетDecimal('NaN'), если number является тихим NaN. ВызываетInvalidOperation, если number является бесконечностью, сигнальным NaN, или если длина коэффициента после операции quantize превышает точность текущего контекста. Иными словами, для неграничных случаев:если ndigits положителен, возвращает number, округлённый до ndigits десятичных знаков;
если ndigits равен нулю, возвращает number, округлённый до ближайшего целого;
если ndigits отрицателен, возвращает number, округлённый до ближайшего кратного
10**abs(ndigits).
Например:
>>> from decimal import Decimal, getcontext, ROUND_DOWN >>> getcontext().rounding = ROUND_DOWN >>> round(Decimal('3.75')) # Округление контекста игнорируется 4 >>> round(Decimal('3.5')) # округление до ближайшего чётного 4 >>> round(Decimal('3.75'), 0) # использует округление контекста Decimal('3') >>> round(Decimal('3.75'), 1) Decimal('3.7') >>> round(Decimal('3.75'), -1) Decimal('0E+1')
Логические операнды¶Logical operands
Методы logical_and(), logical_invert(), logical_or() и logical_xor() ожидают, что их аргументы будут логическими операндами. Логический операнд – это экземпляр Decimal, у которого экспонента и знак равны нулю, а все цифры равны либо 0, либо 1.
Объекты контекста¶Context objects
Контексты – это среды для арифметических операций. Они управляют точностью, задают правила округления, определяют, какие сигналы обрабатываются как исключения, и ограничивают диапазон для экспонент.
Каждый поток имеет собственный текущий контекст, доступ к которому или изменение которого осуществляется с помощью функций 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 # Выполнить вычисление с высокой точностью s = calculate_something() s = +s # Округлить конечный результат до стандартной точности
С использованием именованных аргументов код будет следующим:
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, описанного ниже. Кроме того, модуль предоставляет три готовых контекста:
- decimal.BasicContext¶
Это стандартный контекст, определённый спецификацией General Decimal Arithmetic Specification. Точность установлена в девять. Округление установлено в
ROUND_HALF_UP. Все флаги сброшены. Все ловушки включены (обрабатываются как исключения), кромеInexact,RoundedиSubnormal.Поскольку многие ловушки включены, этот контекст полезен для отладки.
- decimal.ExtendedContext¶
Это стандартный контекст, определённый спецификацией General Decimal Arithmetic Specification. Точность установлена в девять. Округление установлено в
ROUND_HALF_EVEN. Все флаги сброшены. Никакие ловушки не включены (поэтому исключения не возникают во время вычислений).Поскольку ловушки отключены, этот контекст полезен для приложений, которые предпочитают получать в результате значения
NaNилиInfinityвместо возбуждения исключений. Это позволяет приложению завершить выполнение при наличии условий, которые в противном случае остановили бы программу.
- 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 содержат список сигналов, которые необходимо установить. Как правило, для новых контекстов следует задавать только ловушки (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, которое является минимальным значением экспоненты для субнормальных результатов. При антипереполнении (underflow) экспонента устанавливается в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.
- logb(x)¶
Возвращает показатель степени величины старшего разряда операнда.
- 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 соответствует унарному префиксному оператору плюс в 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)¶
Преобразует в строку, используя инженерную запись, если нужен показатель степени.
В инженерной записи показатель степени кратен трём. Из-за этого слева от десятичной запятой может оставаться до трёх цифр, и может потребоваться добавление одного или двух конечных нулей.
- to_integral_exact(x)¶
Округляет до целого.
- to_sci_string(x)¶
Преобразует число в строку, используя научную запись.
Константы¶Constants
Константы в этом разделе имеют значение только для модуля 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.8.3.
Режимы округления¶Rounding modes
- 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; в противном случае округление к нулю.
Сигналы¶Signals
Сигналы представляют условия, возникающие во время вычислений. Каждый соответствует одному флагу контекста и одному включателю ловушки контекста.
Флаг контекста устанавливается при возникновении условия. После вычисления флаги могут быть проверены в информационных целях (например, чтобы определить, было ли вычисление точным). После проверки флагов необходимо очистить все флаги перед началом следующего вычисления.
Если для сигнала установлен включатель ловушки контекста, то условие вызывает возбуждение исключения Python. Например, если установлена ловушка DivisionByZero, то при возникновении условия возбуждается исключение DivisionByZero.
- class decimal.Clamped¶
Изменён показатель степени для соответствия ограничениям представления.
Обычно усечение происходит, когда показатель степени выходит за пределы ограничений контекста
EminиEmax. Если возможно, показатель степени уменьшается для соответствия путём добавления нулей к коэффициенту.
- class decimal.DecimalException¶
Базовый класс для других сигналов и подкласс
ArithmeticError.
- class decimal.DivisionByZero¶
Сигнализирует о делении небесконечного числа на ноль.
Может возникнуть при делении, делении по модулю или при возведении числа в отрицательную степень. Если этот сигнал не перехвачен, возвращает
Infinityили-Infinityсо знаком, определяемым входными данными вычисления.
- class decimal.Inexact¶
Указывает, что произошло округление и результат не является точным.
Сигнализирует, когда при округлении были отброшены ненулевые цифры. Возвращается округлённый результат. Флаг сигнала или ловушка используется для обнаружения неточных результатов.
- class decimal.InvalidOperation¶
Выполнена недопустимая операция.
Указывает, что была запрошена операция, не имеющая смысла. Если не перехвачена, возвращает
NaN. Возможные причины включают:Infinity - Infinity 0 * Infinity Infinity / Infinity x % 0 Infinity % x sqrt(-x) and x > 0 0 ** 0 x ** (non-integer) x ** Infinity
- class decimal.Overflow¶
Числовое переполнение.
Указывает, что показатель степени больше
Context.Emaxпосле округления. Если не перехвачена, результат зависит от режима округления: либо округление внутрь до наибольшего представимого конечного числа, либо округление наружу доInfinity. В любом случае также сигнализируютсяInexactиRounded.
- class decimal.Rounded¶
Произошло округление, хотя, возможно, информация не была потеряна.
Срабатывает при каждом округлении, отбрасывающем цифры, даже если эти цифры нулевые (например, при округлении
5.00до5.0). Если не перехвачено, возвращает результат без изменений. Этот сигнал используется для обнаружения потери значащих цифр.
- class decimal.Subnormal¶
Экспонента была меньше
Eminперед округлением.Возникает, когда результат операции является субнормальным (экспонента слишком мала). Если не перехвачено, возвращает результат без изменений.
- class decimal.Underflow¶
Числовое исчерпание с округлением результата до нуля.
Возникает, когда субнормальный результат округляется до нуля. Также срабатывают сигналы
InexactиSubnormal.
- class decimal.FloatOperation¶
Включает более строгую семантику смешивания чисел с плавающей запятой и десятичных чисел.
Если сигнал не перехвачен (по умолчанию), смешивание чисел с плавающей запятой и десятичных чисел разрешено в конструкторе
Decimal,create_decimal()и во всех операторах сравнения. Как преобразование, так и сравнение являются точными. Любое смешанное действие молча регистрируется установкойFloatOperationв флагах контекста. Явные преобразования с помощьюfrom_float()илиcreate_decimal_from_float()не устанавливают флаг.В противном случае (сигнал перехвачен), молчаливыми остаются только сравнения на равенство и явные преобразования. Все остальные смешанные операции возбуждают
FloatOperation.
В следующей таблице приведена иерархия сигналов:
exceptions.ArithmeticError(exceptions.Exception)
DecimalException
Clamped
DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
Inexact
Overflow(Inexact, Rounded)
Underflow(Inexact, Rounded, Subnormal)
InvalidOperation
Rounded
Subnormal
FloatOperation(DecimalException, exceptions.TypeError)
Примечания о числах с плавающей запятой¶Floating-Point Notes
Снижение ошибки округления за счёт увеличения точности¶Mitigating round-off error with increased precision
Использование десятичной арифметики с плавающей запятой устраняет ошибку десятичного представления (позволяя точно представить 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')
Особые значения¶Special values
Система чисел модуля 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. Попытка сравнить два Decimal с помощью любого из операторов <,
<=, > или >= возбуждает сигнал InvalidOperation,
если хотя бы один операнд является NaN, и возвращает False, если этот сигнал
не перехвачен. Обратите внимание, что спецификация General Decimal Arithmetic не
определяет поведение прямых сравнений; эти правила для сравнений,
включающих NaN, взяты из стандарта IEEE 854 (см. Таблицу 3 в
разделе 5.7). Для обеспечения строгого соответствия стандартам используйте вместо этого методы compare()
и compare_signal().
Знаковые нули могут возникать в результате вычислений, приводящих к исчерпанию. Они сохраняют знак, который получился бы, если бы вычисления выполнялись с большей точностью. Поскольку их величина равна нулю, положительный и отрицательный нули считаются равными, а их знак является информационным.
Помимо двух знаковых нулей, которые различны, но равны, существуют различные представления нуля с разной точностью, но эквивалентные по значению. К этому нужно немного привыкнуть. Для глаза, привыкшего к нормализованным представлениям с плавающей запятой, не сразу очевидно, что следующий расчёт возвращает значение, равное нулю:
>>> 1 / Decimal('Infinity')
Decimal('0E-1000026')
Работа с потоками¶Working with threads
Функция getcontext() обращается к разным объектам Context для
каждого потока. Наличие отдельных контекстов потоков означает, что потоки могут вносить
изменения (например, getcontext().prec=10), не мешая друг другу.
Аналогично, функция setcontext() автоматически назначает свою цель текущему потоку.
Если setcontext() не был вызван до getcontext(), то
getcontext() автоматически создаст новый контекст для использования в
текущем потоке.
Новый контекст копируется из прототипа контекста под названием DefaultContext. Чтобы
управлять значениями по умолчанию так, чтобы каждый поток использовал одни и те же значения во всём
приложении, напрямую измените объект DefaultContext. Это следует сделать
до запуска любых потоков, чтобы не возникло состояния гонки между
потоками, вызывающими getcontext(). Например:
# Установить глобальные настройки по умолчанию для всех потоков, которые будут запущены
DefaultContext.prec = 12
DefaultContext.rounding = ROUND_DOWN
DefaultContext.traps = ExtendedContext.traps.copy()
DefaultContext.traps[InvalidOperation] = 1
setcontext(DefaultContext)
# После этого потоки можно запускать
t1.start()
t2.start()
t3.start()
. . .
Рецепты¶Recipes
Вот несколько рецептов, которые служат вспомогательными функциями и демонстрируют способы работы с классом Decimal:
def moneyfmt(value, places=2, curr='', sep=',', dp='.',
pos='', neg='-', trailneg=''):
"""Преобразовать Decimal в строку, отформатированную как денежная сумма.
places: обязательное количество знаков после десятичной точки
curr: необязательный символ валюты перед знаком (может быть пустым)
sep: необязательный разделитель групп (запятая, точка, пробел или пусто)
dp: указатель десятичной точки (запятая или точка)
указывать пустым только при places=0
pos: необязательный знак для положительных чисел: '+', пробел или пусто
neg: необязательный знак для отрицательных чисел: '-', '(', пробел или пусто
trailneg:необязательный завершающий знак минуса: '-', ')', пробел или пусто
>>> 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 знака после запятой --> '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():
"""Вычислить число Пи с текущей точностью.
>>> print(pi())
3.141592653589793238462643383
"""
getcontext().prec += 2 # дополнительные цифры для промежуточных шагов
three = Decimal(3) # подставить "three=3.0" вместо обычных чисел с плавающей точкой
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 # унарный плюс применяет новую точность
def exp(x):
"""Возвращает e, возведённое в степень x. Тип результата соответствует типу входного значения.
>>> 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):
"""Возвращает косинус x, измеренного в радианах.
Аппроксимация рядом Тейлора даёт наилучший результат при малых значениях x.
Для больших значений сначала вычислите 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):
"""Возвращает синус угла x, заданного в радианах.
Аппроксимация рядом Тейлора даёт наилучший результат при малых значениях x.
Для больших значений сначала вычислите x = x % (2 * pi).
>>> print(sin(Decimal('0.5')))
0.4794255386042030002732879352
>>> print(sin(0.5))
0.479425538604
>>> print(sin(0.5+0j))
(0.479425538604+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1
while s != lasts:
lasts = s
i += 2
fact *= i * (i-1)
num *= x * x
sign *= -1
s += num / fact * sign
getcontext().prec -= 2
return +s
Вопросы и ответы по Decimal¶Decimal FAQ
Вопрос. Вводить decimal.Decimal('1234.5') неудобно. Есть ли способ сократить набор при работе в интерактивном интерпретаторе?
Ответ. Некоторые пользователи сокращают конструктор до одной буквы:
>>> D = decimal.Decimal
>>> D('1.23') + D('3.45')
Decimal('4.68')
Вопрос. В приложении с фиксированной запятой с двумя десятичными знаками некоторые входные данные имеют много знаков и нуждаются в округлении. Другие не должны содержать лишних цифр и требуют проверки. Какие методы следует использовать?
Ответ. Метод quantize() округляет до заданного числа десятичных знаков. Если установлен перехват Inexact, он также полезен для проверки:
>>> TWOPLACES = Decimal(10) ** -2 # то же, что Decimal('0.01')
>>> # Округлить до двух знаков
>>> Decimal('3.214').quantize(TWOPLACES)
Decimal('3.21')
>>> # Проверка, что число не выходит за пределы двух знаков
>>> 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') # Начальные значения чисел с фиксированной точкой
>>> b = Decimal('3.17')
>>> a + b # Сложение сохраняет фиксированную точку
Decimal('105.89')
>>> a - b
Decimal('99.55')
>>> a * 42 # Умножение на целое число – тоже
Decimal('4314.24')
>>> (a * b).quantize(TWOPLACES) # Результат умножения на нецелое число нужно квантовать
Decimal('325.62')
>>> (b / a).quantize(TWOPLACES) # И квантовать результат деления
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) # Автоматически сохранять фиксированную точку
Decimal('325.62')
>>> div(b, a)
Decimal('0.03')
Вопрос. Существует много способов выразить одно и то же значение. Числа 200, 200.000, 2E2 и .02E+4 при различной точности имеют одно и то же значение. Есть ли способ преобразовать их в единое узнаваемое каноническое значение?
Ответ. Метод normalize() отображает все эквивалентные значения в единого представителя:
>>> values = map(Decimal, '200 200.000 2E2 .02E+4'.split())
>>> [v.normalize() for v in values]
[Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2')]
Вопрос. Когда происходит округление в вычислениях?
Ответ. Округление происходит после вычисления. Философия спецификации decimal заключается в том, что числа считаются точными и создаются независимо от текущего контекста. Они могут иметь даже большую точность, чем текущий контекст. Вычисления обрабатывают эти точные входные данные, а затем округление (или другие операции контекста) применяется к результату вычисления:
>>> getcontext().prec = 5
>>> pi = Decimal('3.1415926535') # Более 5 цифр
>>> pi # Все цифры сохраняются
Decimal('3.1415926535')
>>> pi + 0 # Округляется после сложения
Decimal('3.1416')
>>> pi - Decimal('0.00005') # Вычесть неокруглённые числа, затем округлить
Decimal('3.1415')
>>> pi + 0 - Decimal('0.00005'). # Промежуточные значения округляются
Decimal('3.1416')
Вопрос. Некоторые значения decimal всегда выводятся в экспоненциальной записи. Есть ли способ получить неэкспоненциальное представление?
Ответ. Для некоторых значений экспоненциальная запись – единственный способ выразить количество значащих цифр в коэффициенте. Например, представление 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')
Вопрос. Есть ли способ преобразовать обычный float в Decimal?
Ответ. Да, любое двоичное число с плавающей запятой можно точно выразить как Decimal, хотя точное преобразование может потребовать большей точности, чем кажется интуитивно:
>>> Decimal(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875')
Вопрос. В сложном вычислении как я могу убедиться, что не получил ложный результат из-за недостаточной точности или аномалий округления?
Ответ. Модуль decimal упрощает проверку результатов. Рекомендуется перезапускать вычисления с большей точностью и различными режимами округления. Сильно различающиеся результаты указывают на недостаточную точность, проблемы с режимом округления, плохо обусловленные входные данные или численно неустойчивый алгоритм.
Вопрос. Я заметил, что точность контекста применяется к результатам операций, но не к входным данным. Есть ли что-то, на что следует обращать внимание при смешивании значений разной точности?
Ответ. Да. Принцип заключается в том, что все значения считаются точными, как и арифметические операции с ними. Округляются только результаты. Преимущество для входных данных в том, что «что ввёл, то и получил». Недостаток в том, что результаты могут выглядеть странно, если забыть, что входные данные не округлены:
>>> getcontext().prec = 3
>>> Decimal('3.104') + Decimal('2.104')
Decimal('5.21')
>>> Decimal('3.104') + Decimal('0.000') + Decimal('2.104')
Decimal('5.20')
Решение – либо увеличить точность, либо принудительно округлить входные данные с помощью унарного плюса:
>>> getcontext().prec = 3
>>> +Decimal('1.23456789') # Унарный плюс вызывает округление
Decimal('1.23')
В качестве альтернативы входные данные можно округлить при создании с помощью метода Context.create_decimal():
>>> Context(prec=5, rounding=ROUND_DOWN).create_decimal('1.2345678')
Decimal('1.2345')
Вопрос. Быстра ли реализация CPython для больших чисел?
Ответ. Да. В реализациях CPython и PyPy3 версии C/CFFI модуля decimal подключают высокоскоростную библиотеку 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
>>>
>>> # Максимальное количество цифр для одного операнда при использовании 500 МБ в 8-байтовых словах
>>> # с 19 цифрами на слово (4 байта и 9 цифр для 32-битной сборки):
>>> maxdigits = 19 * ((500 * 1024**2) // 8)
>>>
>>> # Проверить, что это работает:
>>> c = Context(prec=maxdigits, Emax=MAX_EMAX, Emin=MIN_EMIN)
>>> c.traps[Inexact] = True
>>> setcontext(c)
>>>
>>> # Заполнить доступную точность девятками:
>>> 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, если ожидается, что все вычисления будут точными.
Эта страница – перевод. Оригинал на английском – docs.python.org. Нашли неточность? Сообщите нам.