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: Спецификация общей десятичной арифметики.
Краткое руководство
Обычно для начала работы с десятичными числами импортируют модуль, просматривают текущий контекст с помощью 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')
Десятичные числа можно форматировать (с помощью встроенной функции format() или f-строк) в формате с фиксированной точкой или в экспоненциальной нотации, используя тот же синтаксис форматирования (см. Мини-язык спецификаций формата), что и для встроенного типа float:
>>> format(Decimal('2.675'), "f")
'2.675'
>>> format(Decimal('2.675'), ".2f")
'2.68'
>>> f"{Decimal('2.675'):.2f}"
'2.68'
>>> format(Decimal('2.675'), ".2e")
'2.68e+0'
>>> with localcontext() as ctx:
... ctx.rounding = ROUND_DOWN
... print(format(Decimal('2.675'), ".2f"))
...
2.67
Для 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
Вместо
digit, указанного выше, также допускаются другие десятичные цифры Unicode. К ним относятся десятичные цифры из различных других алфавитов (например, арабско-индийские цифры и цифры деванагари), а также полноширинные цифры от'\uff10'до'\uff19'. Регистр не имеет значения, поэтому, например,inf,Inf,INFINITYиiNfINity— допустимые варианты записи положительной бесконечности.Если 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. К ним применимы все обычные математические операции и специальные методы. Аналогично, объекты Decimal можно копировать, сериализовать с помощью pickle, выводить, использовать в качестве ключей словарей и элементов множеств, сравнивать, сортировать и преобразовывать в другой тип (например,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и другими числовыми типами.Помимо стандартных числовых свойств, десятичные числа с плавающей точкой имеют ряд специализированных методов:
-
adjusted() -
Возвращает скорректированный показатель степени, полученный удалением крайних правых цифр коэффициента до тех пор, пока не останется только старшая цифра:
Decimal('321e+5').adjusted()возвращает семь. Используется для определения положения самой значащей цифры относительно десятичной точки.
-
as_integer_ratio() -
Возвращает пару
(n, d)целых чисел, представляющих заданный экземплярDecimalв виде дроби, несократимой и с положительным знаменателем:>>> Decimal('-3.14').as_integer_ratio() (-157, 50)Преобразование выполняется точно. Для бесконечностей возникает OverflowError, а для NaN — ValueError.
Добавлено в версии 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.
-
classmethod from_number(number, /) -
Альтернативный конструктор, принимающий только экземпляры
float,intилиDecimal, но не строки или кортежи.>>> Decimal.from_number(314) Decimal('314') >>> Decimal.from_number(0.1) Decimal('0.1000000000000000055511151231257827021181583404541015625') >>> Decimal.from_number(Decimal('3.14')) Decimal('3.14')Добавлено в версии 3.14.
-
fma(other, third, context=None) -
Умножение с последующим сложением без промежуточного округления. Возвращает self*other+third без округления промежуточного произведения self*other.
>>> Decimal(2).fma(3, 5) Decimal('11')
-
is_canonical() -
Возвращает
True, если аргумент канонический, иFalseв противном случае. В настоящее время экземплярDecimalвсегда является каноническим, поэтому эта операция всегда возвращаетTrue.
-
is_finite() -
Возвращает
True, если аргумент является конечным числом, иFalse, если аргумент — бесконечность или NaN.
-
is_infinite() -
Возвращает
True, если аргумент является положительной или отрицательной бесконечностью, иFalseв противном случае.
-
is_nan() -
Возвращает
True, если аргумент — (тихий или сигнализирующий) NaN, иFalseв противном случае.
-
is_normal(context=None) -
Возвращает
True, если аргумент является нормальным конечным числом. ВозвращаетFalse, если аргумент равен нулю, является субнормальным, бесконечным или NaN.
-
is_signed() -
Возвращает
True, если аргумент имеет отрицательный знак, иFalseв противном случае. Обратите внимание, что нули и NaN могут иметь знак.
-
is_subnormal(context=None) -
Возвращает
True, если аргумент является субнормальным, иFalseв противном случае.
-
is_zero() -
Возвращает
True, если аргумент равен (положительному или отрицательному) нулю, иFalseв противном случае.
-
ln(context=None) -
Возвращает натуральный логарифм (по основанию e) операнда. Результат правильно округляется с использованием режима округления
ROUND_HALF_EVEN.
-
log10(context=None) -
Возвращает десятичный логарифм операнда. Результат правильно округляется с использованием режима округления
ROUND_HALF_EVEN.
-
logb(context=None) -
Для ненулевого числа возвращает скорректированный показатель степени операнда в виде экземпляра
Decimal. Если операнд равен нулю, возвращаетсяDecimal('-Infinity')и устанавливается флагDivisionByZero. Если операнд — бесконечность, возвращаетсяDecimal('Infinity').
-
logical_and(other, context=None) -
logical_and()— логическая операция, принимающая два логических операнда (см. Логические операнды). Результатом является побитовоеandдвух операндов поразрядно.
-
logical_invert(context=None) -
logical_invert()— логическая операция. Результатом является инверсия каждого разряда операнда.
-
logical_or(other, context=None) -
logical_or()— логическая операция, принимающая два логических операнда (см. Логические операнды). Результатом является побитовоеorдвух операндов поразрядно.
-
logical_xor(other, context=None) -
logical_xor()— логическая операция, принимающая два логических операнда (см. Логические операнды). Результатом является поразрядная операция исключающего ИЛИ для двух операндов.
-
max(other, context=None) -
Аналогичен
max(self, other), за исключением того, что перед возвратом применяется правило округления контекста, а значенияNaNлибо вызывают сигнал, либо игнорируются (в зависимости от контекста и от того, являются ли они сигнализирующими или тихими).
-
max_mag(other, context=None) -
Похож на метод
max(), но сравнение выполняется по абсолютным значениям операндов.
-
min(other, context=None) -
Аналогичен
min(self, other), за исключением того, что перед возвратом применяется правило округления контекста, а значенияNaNлибо вызывают сигнал, либо игнорируются (в зависимости от контекста и от того, являются ли они сигнализирующими или тихими).
-
min_mag(other, context=None) -
Похож на метод
min(), но сравнение выполняется по абсолютным значениям операндов.
-
next_minus(context=None) -
Возвращает наибольшее число, представимое в заданном контексте (или в контексте текущего потока, если контекст не задан), которое меньше заданного операнда.
-
next_plus(context=None) -
Возвращает наименьшее число, представимое в заданном контексте (или в контексте текущего потока, если контекст не задан), которое больше заданного операнда.
-
next_toward(other, context=None) -
Если операнды не равны, возвращает число, ближайшее к первому операнду в направлении второго. Если оба операнда численно равны, возвращает копию первого операнда со знаком, совпадающим со знаком второго операнда.
-
normalize(context=None) -
Используется для получения канонических значений класса эквивалентности в текущем или указанном контексте.
Семантика этого метода совпадает с семантикой унарного оператора «плюс», за исключением того, что конечный результат приводится к простейшей форме: все конечные нули удаляются, а знак сохраняется. То есть, пока коэффициент ненулевой и кратен десяти, он делится на десять, а показатель степени увеличивается на 1. В противном случае (если коэффициент равен нулю) показатель степени устанавливается в 0. Во всех случаях знак не меняется.
Например,
Decimal('32.100')иDecimal('0.321000e+2')нормализуются до эквивалентного значенияDecimal('32.1').Обратите внимание, что округление выполняется до приведения к простейшей форме.
В последних версиях спецификации эта операция также называется
reduce.
-
number_class(context=None) -
Возвращает строку, описывающую класс операнда. Возвращаемое значение — одна из следующих десяти строк.
-
"-Infinity"— операнд является отрицательной бесконечностью. -
"-Normal"— операнд является отрицательным нормальным числом. -
"-Subnormal"— операнд отрицателен и является субнормальным. -
"-Zero"— операнд является отрицательным нулем. -
"+Zero"— операнд является положительным нулем. -
"+Subnormal"— операнд положителен и является субнормальным. -
"+Normal"— операнд является положительным нормальным числом. -
"+Infinity"— операнд является положительной бесконечностью. -
"NaN"— операнд является тихим NaN (не числом). -
"sNaN"— операнд является сигнализирующим NaN.
-
-
quantize(exp, rounding=None, context=None) -
Возвращает значение, равное первому операнду после округления и имеющее показатель степени второго операнда.
>>> Decimal('1.41421356').quantize(Decimal('1.000')) Decimal('1.414')В отличие от других операций, если длина коэффициента после операции quantize превышает точность, возникает сигнал
InvalidOperation. Это гарантирует, что при отсутствии ошибки показатель степени результата quantize всегда равен показателю степени правого операнда.Кроме того, в отличие от других операций, 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) -
Преобразует значение в строку, используя инженерную нотацию, если требуется показатель степени.
В инженерной нотации показатель степени кратен 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. Если не указан ни один из параметров, используется режим округления текущего контекста.
-
to_integral_value(rounding=None, context=None) -
Округляет до ближайшего целого числа, не сигнализируя
InexactилиRounded. Если задан параметр rounding, он применяется; в противном случае используется метод округления из переданного context или текущего контекста.
Десятичные числа можно округлять с помощью функции
round():- round(number)
- round(number, ndigits)
-
Если ndigits не задан или равен
None, возвращает ближайшееintк number, округляя значения посередине до ближайшего чётного, и игнорируя режим округления контекста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')) # context rounding ignored 4 >>> round(Decimal('3.5')) # round-ties-to-even 4 >>> round(Decimal('3.75'), 0) # uses the context rounding Decimal('3') >>> round(Decimal('3.75'), 1) Decimal('3.7') >>> round(Decimal('3.75'), -1) Decimal('0E+1')
-
Логические операнды
Методы logical_and(), logical_invert(), logical_or() и logical_xor() ожидают, что их аргументы будут логическими операндами. Логический операнд — это экземпляр Decimal, показатель степени и знак которого равны нулю, а все цифры — 0 или 1.
Объекты контекста
Контексты представляют собой среды для арифметических операций. Они управляют точностью, задают правила округления, определяют, какие сигналы считаются исключениями, и ограничивают диапазон показателей степени.
У каждого потока есть собственный текущий контекст, к которому можно обратиться или который можно изменить с помощью функций getcontext() и setcontext():
-
decimal.getcontext() -
Возвращает текущий контекст активного потока.
-
decimal.setcontext(c, /) -
Устанавливает c в качестве текущего контекста активного потока.
Для временного изменения активного контекста также можно использовать инструкцию with и функцию localcontext().
-
decimal.localcontext(ctx=None, **kwargs) -
Возвращает менеджер контекста, который при входе в инструкцию with установит в качестве текущего контекста активного потока копию ctx, а при выходе из инструкции with восстановит предыдущий контекст. Если контекст не указан, используется копия текущего контекста. Аргумент kwargs используется для установки атрибутов нового контекста.
Например, следующий код устанавливает текущую точность десятичной арифметики равной 42 знакам, выполняет вычисление, а затем автоматически восстанавливает предыдущий контекст:
from decimal import localcontext with localcontext() as ctx: ctx.prec = 42 # Perform a high precision calculation s = calculate_something() s = +s # Round the final result back to the default precisionС использованием именованных аргументов код будет выглядеть так:
from decimal import localcontext with localcontext(prec=42) as ctx: s = calculate_something() s = +sВызывает
TypeError, если kwargs задаёт атрибут, который не поддерживаетсяContext. ВызываетTypeErrorилиValueError, если kwargs задаёт недопустимое значение атрибута.Изменено в версии 3.11:
localcontext()теперь поддерживает установку атрибутов контекста с помощью именованных аргументов.
-
decimal.IEEEContext(bits) -
Возвращает объект контекста, инициализированный подходящими значениями для одного из форматов обмена IEEE. Аргумент должен быть кратен 32 и меньше
IEEE_CONTEXT_MAX_BITS.Добавлено в версии 3.14.
Новые контексты также можно создавать с помощью описанного ниже конструктора Context. Кроме того, модуль предоставляет три готовых контекста:
-
decimal.BasicContext -
Это стандартный контекст, определённый спецификацией General Decimal Arithmetic. Точность установлена равной девяти. Округление выполняется по правилу
ROUND_HALF_UP. Все флаги сброшены. Все ловушки включены (обрабатываются как исключения), кромеInexact,RoundedиSubnormal.Поскольку включено много ловушек, этот контекст полезен для отладки.
-
decimal.ExtendedContext -
Это стандартный контекст, определённый спецификацией General Decimal Arithmetic. Точность установлена равной девяти. Округление выполняется по правилу
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 -
Списки сигналов, которые следует установить. Как правило, в новых контекстах следует устанавливать только ловушки, оставляя флаги сброшенными.
-
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='0', /) -
Создаёт новый экземпляр 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, /) -
Возвращает натуральный логарифм x (по основанию e).
-
log10(x, /) -
Возвращает десятичный логарифм x (по основанию 10).
-
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, /) -
Minus соответствует унарному префиксному оператору минус в Python.
-
multiply(x, y, /) -
Возвращает произведение x и y.
-
next_minus(x, /) -
Возвращает наибольшее представимое число, меньшее x.
-
next_plus(x, /) -
Возвращает наименьшее представимое число, большее x.
-
next_toward(x, y, /) -
Возвращает число, ближайшее к x в направлении к y.
-
normalize(x, /) -
Приводит x к простейшей форме.
-
number_class(x, /) -
Возвращает признак класса числа x.
-
plus(x, /) -
Plus соответствует унарному префиксному оператору плюс в 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. Если Python собран с параметромconfigured using the --without-decimal-contextvar option, версия на C использует контекст, локальный для потока, а не для сопрограммы, и значение равноFalse. В некоторых сценариях с вложенными контекстами это немного быстрее.Добавлено в версии 3.8.3.
Режимы округления
-
decimal.ROUND_CEILING -
Округление в направлении
Infinity.
-
decimal.ROUND_DOWN -
Округление в сторону нуля.
-
decimal.ROUND_FLOOR -
Округление в направлении
-Infinity.
-
decimal.ROUND_HALF_DOWN -
Округление до ближайшего значения; при равном удалении — в сторону нуля.
-
decimal.ROUND_HALF_EVEN -
Округление до ближайшего значения; при равном удалении — до ближайшего чётного целого.
-
decimal.ROUND_HALF_UP -
Округление до ближайшего значения; при равном удалении — от нуля.
-
decimal.ROUND_UP -
Округление от нуля.
-
decimal.ROUND_05UP -
Округление от нуля, если последняя цифра после округления в сторону нуля была бы равна 0 или 5; в противном случае — в сторону нуля.
Сигналы
Сигналы обозначают условия, возникающие во время вычислений. Каждому сигналу соответствует один флаг контекста и один переключатель ловушки контекста.
Флаг контекста устанавливается при каждом возникновении соответствующего условия. После вычисления флаги можно проверить в информационных целях (например, чтобы определить, было ли вычисление точным). После проверки флагов обязательно сбросьте их все перед началом следующего вычисления.
Если для сигнала включена ловушка контекста, возникновение соответствующего условия приводит к возбуждению исключения 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.
Если сигнал не перехватывается (по умолчанию), смешивание чисел с плавающей точкой и Decimal допускается в конструкторе
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. Попытка сравнить два Decimal с помощью любого из операторов <, <=, > или >= вызывает сигнал InvalidOperation, если один из операндов — NaN, и возвращает False, если этот сигнал не перехватывается. Обратите внимание, что спецификация General Decimal Arithmetic не определяет поведение прямых сравнений; эти правила для сравнений с участием NaN взяты из стандарта IEEE 854 (см. таблицу 3 в разделе 5.7). Для строгого соответствия стандартам используйте методы compare() и compare_signal().
Знаковые нули могут возникать в результате вычислений, приводящих к исчезновению порядка. Они сохраняют знак, который получился бы, если бы вычисление выполнялось с большей точностью. Поскольку их величина равна нулю, положительный и отрицательный нули считаются равными, а их знак носит информационный характер.
Помимо двух знаковых нулей, которые различны, но равны, существуют различные представления нуля с разной точностью, но эквивалентные по значению. К этому нужно привыкнуть. Для тех, кто привык к нормализованным представлениям чисел с плавающей точкой, не сразу очевидно, что следующее вычисление возвращает значение, равное нулю:
>>> 1 / Decimal('Infinity')
Decimal('0E-1000026')
Работа с потоками
Функция getcontext() обращается к отдельному объекту Context для каждого потока. Наличие отдельных контекстов потоков позволяет потокам вносить изменения (например, getcontext().prec=10), не мешая работе других потоков.
Аналогично, функция setcontext() автоматически назначает целевой контекст текущему потоку.
Если перед вызовом getcontext() функция setcontext() не вызывалась, то getcontext() автоматически создаст новый контекст для использования в текущем потоке. Для новых объектов контекста устанавливаются значения по умолчанию из объекта decimal.DefaultContext.
Флаг sys.flags.thread_inherit_context влияет на контекст новых потоков. Если флаг имеет значение false, новые потоки начинают работу с пустым контекстом. В этом случае при вызове getcontext() создаётся новый объект контекста, использующий значения по умолчанию из DefaultContext. Если флаг имеет значение true, новые потоки начинают работу с копией контекста вызывающего потока, в котором был вызван threading.Thread.start().
Чтобы задать значения по умолчанию, которые будут использоваться всеми потоками на протяжении работы приложения, измените непосредственно объект DefaultContext. Это следует сделать до запуска любых потоков, чтобы избежать состояния гонки между потоками, вызывающими getcontext(). Например:
# Set applicationwide defaults for all threads about to be launched DefaultContext.prec = 12 DefaultContext.rounding = ROUND_DOWN DefaultContext.traps = ExtendedContext.traps.copy() DefaultContext.traps[InvalidOperation] = 1 setcontext(DefaultContext) # Afterwards, the threads can be started t1.start() t2.start() t3.start() . . .
Примеры
Ниже приведено несколько примеров служебных функций, демонстрирующих способы работы с классом Decimal:
def moneyfmt(value, places=2, curr='', sep=',', dp='.',
pos='', neg='-', trailneg=''):
"""Convert Decimal to a money formatted string.
places: required number of places after the decimal point
curr: optional currency symbol before the sign (may be blank)
sep: optional grouping separator (comma, period, space, or blank)
dp: decimal point indicator (comma or period)
only specify as blank when places is zero
pos: optional sign for positive numbers: '+', space or blank
neg: optional sign for negative numbers: '-', '(', space or blank
trailneg:optional trailing minus indicator: '-', ')', space or blank
>>> d = Decimal('-1234567.8901')
>>> moneyfmt(d, curr='$')
'-$1,234,567.89'
>>> moneyfmt(d, places=0, sep='.', dp='', neg='', trailneg='-')
'1.234.568-'
>>> moneyfmt(d, curr='$', neg='(', trailneg=')')
'($1,234,567.89)'
>>> moneyfmt(Decimal(123456789), sep=' ')
'123 456 789.00'
>>> moneyfmt(Decimal('-0.02'), neg='<', trailneg='>')
'<0.02>'
"""
q = Decimal(10) ** -places # 2 places --> '0.01'
sign, digits, exp = value.quantize(q).as_tuple()
result = []
digits = list(map(str, digits))
build, next = result.append, digits.pop
if sign:
build(trailneg)
for i in range(places):
build(next() if digits else '0')
if places:
build(dp)
if not digits:
build('0')
i = 0
while digits:
build(next())
i += 1
if i == 3 and digits:
i = 0
build(sep)
build(curr)
build(neg if sign else pos)
return ''.join(reversed(result))
def pi():
"""Compute Pi to the current precision.
>>> print(pi())
3.141592653589793238462643383
"""
getcontext().prec += 2 # extra digits for intermediate steps
three = Decimal(3) # substitute "three=3.0" for regular floats
lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
while s != lasts:
lasts = s
n, na = n+na, na+8
d, da = d+da, da+32
t = (t * n) / d
s += t
getcontext().prec -= 2
return +s # unary plus applies the new precision
def exp(x):
"""Return e raised to the power of x. Result type matches input type.
>>> print(exp(Decimal(1)))
2.718281828459045235360287471
>>> print(exp(Decimal(2)))
7.389056098930650227230427461
>>> print(exp(2.0))
7.38905609893
>>> print(exp(2+0j))
(7.38905609893+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num = 0, 0, 1, 1, 1
while s != lasts:
lasts = s
i += 1
fact *= i
num *= x
s += num / fact
getcontext().prec -= 2
return +s
def cos(x):
"""Return the cosine of x as measured in radians.
The Taylor series approximation works best for a small value of x.
For larger values, first compute x = x % (2 * pi).
>>> print(cos(Decimal('0.5')))
0.8775825618903727161162815826
>>> print(cos(0.5))
0.87758256189
>>> print(cos(0.5+0j))
(0.87758256189+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num, sign = 0, 0, 1, 1, 1, 1
while s != lasts:
lasts = s
i += 2
fact *= i * (i-1)
num *= x * x
sign *= -1
s += num / fact * sign
getcontext().prec -= 2
return +s
def sin(x):
"""Return the sine of x as measured in radians.
The Taylor series approximation works best for a small value of x.
For larger values, first compute x = x % (2 * pi).
>>> print(sin(Decimal('0.5')))
0.4794255386042030002732879352
>>> print(sin(0.5))
0.479425538604
>>> print(sin(0.5+0j))
(0.479425538604+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1
while s != lasts:
lasts = s
i += 2
fact *= i * (i-1)
num *= x * x
sign *= -1
s += num / fact * sign
getcontext().prec -= 2
return +s
Часто задаваемые вопросы о Decimal
В: Вводить decimal.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')]
В: Когда в ходе вычисления происходит округление?
О: Оно происходит после вычисления. Согласно принципу, лежащему в основе спецификации decimal, числа считаются точными и создаются независимо от текущего контекста. Их точность может даже превышать точность текущего контекста. Вычисления выполняются с этими точными входными данными, а затем округление (или другие операции контекста) применяется к результату вычисления:
>>> getcontext().prec = 5
>>> pi = Decimal('3.1415926535') # More than 5 digits
>>> pi # All digits are retained
Decimal('3.1415926535')
>>> pi + 0 # Rounded after an addition
Decimal('3.1416')
>>> pi - Decimal('0.00005') # Subtract unrounded numbers, then round
Decimal('3.1415')
>>> pi + 0 - Decimal('0.00005'). # Intermediate values are rounded
Decimal('3.1416')
В: Некоторые десятичные значения всегда выводятся в экспоненциальной записи. Можно ли представить их без экспоненты?
О: Для некоторых значений экспоненциальная запись — единственный способ указать количество значащих разрядов в коэффициенте. Например, представление 5.0E+3 в виде 5000 сохраняет значение, но не позволяет показать исходную точность в два десятичных знака.
Если приложению не нужно отслеживать точность, можно легко убрать показатель степени и конечные нули, потеряв точность, но сохранив значение:
>>> def remove_exponent(d): ... return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')
В: Можно ли преобразовать обычное число с плавающей точкой в Decimal?
О: Да, любое двоичное число с плавающей точкой можно точно представить как Decimal, хотя для точного преобразования может потребоваться гораздо большая точность, чем можно предположить:
>>> 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, если все вычисления должны быть точными.
© 2001 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/library/decimal.html