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 превышены, создание Decimal вызывает InvalidOperation:
>>> Decimal("1e9999999999999999999")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
Изменено в версии 3.3.
Десятичные числа хорошо взаимодействуют со многими другими частями Python. Вот небольшой пример использования:
>>> data = list(map(Decimal, '1.34 1.87 3.45 2.35 1.00 0.03 9.25'.split()))
>>> max(data)
Decimal('9.25')
>>> min(data)
Decimal('0.03')
>>> sorted(data)
[Decimal('0.03'), Decimal('1.00'), Decimal('1.34'), Decimal('1.87'),
Decimal('2.35'), Decimal('3.45'), Decimal('9.25')]
>>> sum(data)
Decimal('19.29')
>>> a,b,c = data[:3]
>>> str(a)
'1.34'
>>> float(a)
1.34
>>> round(a, 1)
Decimal('1.3')
>>> int(a)
1
>>> a * 5
Decimal('6.70')
>>> a * b
Decimal('2.5058')
>>> c % a
Decimal('0.77')
Также доступны некоторые математические функции для Decimal:
>>> getcontext().prec = 28
>>> Decimal(2).sqrt()
Decimal('1.414213562373095048801688724')
>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal('10').ln()
Decimal('2.302585092994045684017991455')
>>> Decimal('10').log10()
Decimal('1')
Метод quantize() округляет число до заданного показателя степени. Этот метод полезен для приложений, связанных с деньгами, где результаты часто округляются до определённого числа знаков:
>>> Decimal('7.325').quantize(Decimal('.01'), rounding=ROUND_DOWN)
Decimal('7.32')
>>> Decimal('7.325').quantize(Decimal('1.'), rounding=ROUND_UP)
Decimal('8')
Как показано выше, функция getcontext() предоставляет доступ к текущему контексту и позволяет изменять его настройки. Этот подход удовлетворяет потребности большинства приложений.
Для более сложной работы может быть полезно создать альтернативные контексты с помощью конструктора Context(). Чтобы сделать альтернативный контекст активным, используйте функцию setcontext().
В соответствии со стандартом, модуль decimal предоставляет два готовых стандартных контекста, BasicContext и ExtendedContext. Первый особенно полезен для отладки, поскольку многие из ловушек включены:
>>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN)
>>> setcontext(myothercontext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857142857142857142857142857')
>>> ExtendedContext
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[], traps=[])
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857143')
>>> Decimal(42) / Decimal(0)
Decimal('Infinity')
>>> setcontext(BasicContext)
>>> Decimal(42) / Decimal(0)
Traceback (most recent call last):
File "<pyshell#143>", line 1, in -toplevel-
Decimal(42) / Decimal(0)
DivisionByZero: x / 0
Контексты также имеют флаги сигналов для отслеживания исключительных условий, возникающих при вычислениях. Флаги остаются установленными до явного сброса, поэтому лучше сбрасывать флаги перед каждым набором отслеживаемых вычислений с помощью метода clear_flags().
>>> setcontext(ExtendedContext)
>>> getcontext().clear_flags()
>>> Decimal(355) / Decimal(113)
Decimal('3.14159292')
>>> getcontext()
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])
Элемент flags показывает, что рациональное приближение к пи округлялось (цифры, выходящие за пределы точности контекста, были отброшены), и что результат неточен (некоторые из отброшенных цифр были ненулевыми).
Отдельные ловушки устанавливаются с помощью словаря в атрибуте traps контекста:
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(0)
Decimal('Infinity')
>>> getcontext().traps[DivisionByZero] = 1
>>> Decimal(1) / Decimal(0)
Traceback (most recent call last):
File "<pyshell#112>", line 1, in -toplevel-
Decimal(1) / Decimal(0)
DivisionByZero: x / 0
Большинство программ настраивают текущий контекст только один раз в начале программы. И во многих приложениях данные преобразуются в Decimal с единственным приведением внутри цикла. После настройки контекста и создания десятичных чисел основная часть программы обрабатывает данные так же, как и другие числовые типы Python.
Объекты Decimal
-
class decimal.Decimal(value='0', context=None) -
Создайте новый объект
Decimalна основе value.value может быть целым числом, строкой, кортежем,
floatили другим объектомDecimal. Если value не задано, возвращаетDecimal('0'). Если value — строка, она должна соответствовать синтаксису десятичной числовой строки после удаления начальных и конечных пробелов, а также символов подчеркивания:sign ::= '+' | '-' digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' indicator ::= 'e' | 'E' digits ::= digit [digit]... decimal-part ::= digits '.' [digits] | ['.'] digits exponent-part ::= indicator [sign] digits infinity ::= 'Infinity' | 'Inf' nan ::= 'NaN' [digits] | 'sNaN' [digits] numeric-value ::= decimal-part [exponent-part] | infinity numeric-string ::= [sign] numeric-value | [sign] nan
Также допускаются другие десятичные цифры Юникода, где
digitуказано выше. К ним относятся десятичные цифры из различных других алфавитов (например, арабско-индийские и деванагари цифры) вместе с полноширинными цифрами'\uff10'по'\uff19'.Если value —
tuple, он должен содержать три компонента: знак (0для положительного или1для отрицательного), кортеж цифр и целое значение показателя степени. Например,Decimal((0, (1, 4, 1, 4), -3))возвращаетDecimal('1.414').Если value —
float, двоичное значение с плавающей запятой без потерь преобразуется в его точное десятичное эквивалент. Для этого преобразования часто требуется 53 или более разрядов точности. Например,Decimal(float('1.1'))преобразуется вDecimal('1.100000000000000088817841970012523233890533447265625').Точность context не влияет на то, сколько цифр хранится. Это определяется исключительно количеством цифр в value. Например,
Decimal('3.00000')записывает все пять нулей, даже если точность контекста составляет только три.Цель аргумента context — определить, что делать, если value — неправильная строка. Если контекст ловит
InvalidOperation, генерируется исключение; в противном случае конструктор возвращает новый Decimal со значениемNaN.После создания объекты
Decimalявляются неизменяемыми.Изменено в версии 3.2: Аргумент конструктора теперь может быть экземпляром
float.Изменено в версии 3.3: Аргументы
floatвызывают исключение, если установлена ловушкаFloatOperation. По умолчанию ловушка выключена.Изменено в версии 3.6: Подчеркивания допускаются для группировки, как и с целочисленными и с плавающей запятой литералами в коде.
Объекты десятичных чисел с плавающей запятой обладают многими свойствами других встроенных числовых типов, таких как
floatиint. Применяются все обычные математические операции и специальные методы. Аналогично, объекты десятичных чисел можно копировать, сериализовать, выводить на печать, использовать в качестве ключей словарей, элементов множеств, сравнивать, сортировать и преобразовывать в другой тип (например,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 для бесконечностей и ValueError для NaN.
Добавлен в версии 3.6.
-
as_tuple() -
Возвращает представление числа в виде именованного кортежа:
DecimalTuple(sign, digits, exponent).
-
canonical() -
Возвращает каноническое кодирование аргумента. В настоящее время кодирование экземпляра
Decimalвсегда каноническое, поэтому эта операция возвращает свой аргумент без изменений.
-
compare(other, context=None) -
Сравнивает значения двух экземпляров Decimal.
compare()возвращает экземпляр Decimal, а если один из операндов — NaN, то результат — NaN:a or b is a NaN ==> Decimal('NaN') a < b ==> Decimal('-1') a == b ==> Decimal('0') a > b ==> Decimal('1')
-
compare_signal(other, context=None) -
Эта операция идентична методу
compare(), за исключением того, что все NaN сигнализируют. То есть, если ни один из операндов не является сигнализирующим NaN, любой тихий NaN-операнд обрабатывается так, как будто он был сигнализирующим NaN.
-
compare_total(other, context=None) -
Сравнивает два операнда, используя их абстрактное представление, а не их числовое значение. Аналогично методу
compare(), но результат обеспечивает полное упорядочение экземпляровDecimal. Два экземпляраDecimalс одинаковым числовым значением, но разными представлениями, при таком упорядочении сравниваются как неравные:>>> Decimal('12.0').compare_total(Decimal('12')) Decimal('-1')Тихие и сигнализирующие NaN также включены в полное упорядочение. Результатом этой функции является
Decimal('0')если оба операнда имеют одинаковое представление,Decimal('-1')если первый операнд ниже во всей упорядоченности, чем второй, иDecimal('1')если первый операнд выше во всей упорядоченности, чем второй операнд. Подробности полного упорядочения см. в спецификации.Эта операция не зависит от контекста и является бесшумной: флаги не изменяются и округление не выполняется. В качестве исключения, версия C может сгенерировать InvalidOperation, если второй операнд не может быть преобразован точно.
-
compare_total_mag(other, context=None) -
Сравнивает два операнда по их абстрактному представлению, а не по их значению, как в
compare_total(), но игнорируя знак каждого операнда.x.compare_total_mag(y)эквивалентноx.copy_abs().compare_total(y.copy_abs()).Эта операция не зависит от контекста и является бесшумной: флаги не изменяются и округление не выполняется. В качестве исключения, версия C может сгенерировать InvalidOperation, если второй операнд не может быть преобразован точно.
-
conjugate() -
Просто возвращает self, этот метод нужен только для соответствия спецификации Decimal.
-
copy_abs() -
Возвращает абсолютное значение аргумента. Эта операция не зависит от контекста и является бесшумной: флаги не изменяются и округление не выполняется.
-
-
copy_negate() -
Возвращает отрицание аргумента. Эта операция не зависит от контекста и тиха: флаги не изменяются, и округление не выполняется.
-
copy_sign(other, context=None) -
Возвращает копию первого операнда со знаком, установленным таким же, как знак второго операнда. Например:
>>> Decimal('2.3').copy_sign(Decimal('-1.5')) Decimal('-2.3')Эта операция не зависит от контекста и тиха: флаги не изменяются, и округление не выполняется. В качестве исключения, версия C может вызвать InvalidOperation, если второй операнд не может быть преобразован точно.
-
exp(context=None) -
Возвращает значение функции (натурального) экспоненты
e**xв заданном числе. Результат правильно округляется с использованием режима округленияROUND_HALF_EVEN.>>> Decimal(1).exp() Decimal('2.718281828459045235360287471') >>> Decimal(321).exp() Decimal('2.561702493119680037517373933E+139')
-
classmethod from_float(f) -
Альтернативный конструктор, принимающий только экземпляры
floatилиint.Обратите внимание, что
Decimal.from_float(0.1)не то же самое, чтоDecimal('0.1'). Поскольку 0.1 не точно представим в двоичной плавающей точке, значение хранится как ближайшее представимое значение, которое равно0x1.999999999999ap-4. Это эквивалентное значение в десятичной системе равно0.1000000000000000055511151231257827021181583404541015625.Примечание
Начиная с Python 3.2, экземпляр
Decimalтакже может быть создан непосредственно изfloat.>>> Decimal.from_float(0.1) Decimal('0.1000000000000000055511151231257827021181583404541015625') >>> Decimal.from_float(float('nan')) Decimal('NaN') >>> Decimal.from_float(float('inf')) Decimal('Infinity') >>> Decimal.from_float(float('-inf')) Decimal('-Infinity')Добавлен в версии 3.1.
-
fma(other, third, context=None) -
Объединённое умножение-сложение. Возвращает self*other+third без округления промежуточного произведения self*other.
>>> Decimal(2).fma(3, 5) Decimal('11')
-
is_canonical() -
Возвращает
True, если аргумент каноничен, иFalseв противном случае. В настоящее время экземплярDecimalвсегда каноничен, поэтому эта операция всегда возвращаетTrue.
-
is_finite() -
Возвращает
True, если аргумент является конечным числом, иFalse, если аргумент является бесконечностью или NaN.
-
is_infinite() -
Возвращает
True, если аргумент является положительной или отрицательной бесконечностью, иFalseв противном случае.
-
is_nan() -
Возвращает
True, если аргумент является (тихим или сигнализирующим) NaN, иFalseв противном случае.
-
is_normal(context=None) -
Возвращает
True, если аргумент является нормальным конечным числом. ВозвращаетFalse, если аргумент равен нулю, поднормальному, бесконечному или NaN.
-
is_signed() -
Возвращает
True, если аргумент имеет отрицательный знак, иFalseв противном случае. Обратите внимание, что нули и NaN могут иметь знаки.
-
is_subnormal(context=None) -
Возвращает
True, если аргумент является поднормальным, иFalseв противном случае.
-
is_zero() -
Возвращает
True, если аргумент является (положительным или отрицательным) нулём, иFalseв противном случае.
-
ln(context=None) -
Возвращает натуральный (по основанию e) логарифм операнда. Результат правильно округляется с использованием режима округления
ROUND_HALF_EVEN.
-
log10(context=None) -
Возвращает десятичный логарифм операнда. Результат правильно округляется с использованием режима округления
ROUND_HALF_EVEN.
-
logb(context=None) -
Для ненулевого числа возвращает экспоненту операнда в виде экземпляра
Decimal. Если операнд равен нулю, возвращаетсяDecimal('-Infinity'), а флагDivisionByZeroподнимается. Если операнд является бесконечностью, возвращаетсяDecimal('Infinity').
-
logical_and(other, context=None) -
logical_and()- логическая операция, которая принимает два логических операнда (см. Логические операнды). Результатом является цифроваяandдвух операндов.
-
logical_invert(context=None) -
logical_invert()- логическая операция. Результатом является цифровая инверсия операнда.
-
logical_or(other, context=None) -
logical_or()- логическая операция, которая принимает два логических операнда (см. Логические операнды). Результатом является цифроваяorдвух операндов.
-
logical_xor(other, context=None) -
logical_xor()- логическая операция, которая принимает два логических операнда (см. Логические операнды). Результатом является поразрядное исключающее ИЛИ двух операндов.
-
max(other, context=None) -
Аналогично
max(self, other), за исключением того, что правило округления контекста применяется перед возвратом, и чтоNaNзначения либо сигнализируют, либо игнорируются (в зависимости от контекста и являются ли они сигнализирующими или тихими).
-
max_mag(other, context=None) -
Аналогично методу
max(), но сравнение выполняется с использованием абсолютных значений операндов.
-
min(other, context=None) -
Аналогично
min(self, other), за исключением того, что правило округления контекста применяется перед возвратом, и чтоNaNзначения либо сигнализируют, либо игнорируются (в зависимости от контекста и являются ли они сигнализирующими или тихими).
-
min_mag(other, context=None) -
Аналогично методу
min(), но сравнение выполняется с использованием абсолютных значений операндов.
-
-
next_minus(context=None) -
Возвращает наибольшее число, представимое в данном контексте (или в контексте текущей нити, если контекст не задан), меньшее заданного операнда.
-
next_plus(context=None) -
Возвращает наименьшее число, представимое в данном контексте (или в контексте текущей нити, если контекст не задан), большее заданного операнда.
-
next_toward(other, context=None) -
Если два операнда не равны, возвращает число, ближайшее к первому операнду в направлении второго операнда. Если оба операнда численно равны, возвращает копию первого операнда со знаком, установленным таким же, как знак второго операнда.
-
normalize(context=None) -
Используется для получения канонических значений класса эквивалентности в контексте текущего или указанного контекста.
Эта операция имеет те же семантики, что и унарная операция плюс, за исключением того, что, если конечный результат является конечным, он сводится к своей простейшей форме, с удалением всех конечных нулей и сохранением знака. То есть, пока коэффициент отличен от нуля и кратен десяти, коэффициент делится на десять, а показатель степени увеличивается на 1. В противном случае (коэффициент равен нулю) показатель степени устанавливается в 0. Во всех случаях знак не изменяется.
Например,
Decimal('32.100')иDecimal('0.321000e+2')оба нормализуются до эквивалентного значенияDecimal('32.1').Обратите внимание, что округление применяется перед упрощением до простейшей формы.
В последних версиях спецификации эта операция также известна как
reduce.
-
number_class(context=None) -
Возвращает строку, описывающую класс операнда. Возвращаемое значение является одной из следующих десяти строк.
-
"-Infinity", указывающее, что операнд — отрицательная бесконечность. -
"-Normal", указывающее, что операнд — отрицательное нормальное число. -
"-Subnormal", указывающее, что операнд — отрицательное и субнормальное число. -
"-Zero", указывающее, что операнд — отрицательный ноль. -
"+Zero", указывающее, что операнд — положительный ноль. -
"+Subnormal", указывающее, что операнд — положительное и субнормальное число. -
"+Normal", указывающее, что операнд — положительное нормальное число. -
"+Infinity", указывающее, что операнд — положительная бесконечность. -
"NaN", указывающее, что операнд — тихий NaN (Not a Number). -
"sNaN", указывающее, что операнд — сигнализирующий NaN.
-
-
quantize(exp, rounding=None, context=None) -
Возвращает значение, равное первому операнду после округления и имеющее показатель степени второго операнда.
>>> Decimal('1.41421356').quantize(Decimal('1.000')) Decimal('1.414')В отличие от других операций, если длина коэффициента после операции quantize будет больше точности, то сигнализируется
InvalidOperation. Это гарантирует, что, за исключением случаев ошибок, показатель степени quantized всегда равен показателю степени правого операнда.Также в отличие от других операций, quantize никогда не сигнализирует о переполнении, даже если результат субнормальный и неточный.
Если показатель степени второго операнда больше, чем первого, может потребоваться округление. В этом случае режим округления определяется аргументом
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. При задании применяется округление; в противном случае используется метод округления в предоставленном контексте или в текущем контексте.
Десятичные числа могут быть округлены с помощью функции
round():- round(number)
-
- round(number, ndigits)
-
Если ndigits не указан или
None, возвращает ближайшееintк number, привязывая к чётным, и игнорируя режим округления контекстаDecimal. ВозникаетOverflowError, если number — бесконечность, илиValueError, если это NaN (тихий или сигнализирующий).Если ndigits — целое число, то учитывается режим округления контекста и возвращается
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) -
Возвращает менеджер контекста, который установит текущий контекст для активного потока в копию ctx при входе в инструкцию with и восстановит предыдущий контекст при выходе из инструкции with. Если контекст не указан, используется копия текущего контекста. Аргумент kwargs используется для установки атрибутов нового контекста.
Например, следующий код устанавливает текущую точность десятичных чисел на 42 знака, выполняет вычисление и затем автоматически восстанавливает предыдущий контекст:
from decimal import localcontext with localcontext() as ctx: ctx.prec = 42 # Perform a high precision calculation s = calculate_something() s = +s # Round the final result back to the default precisionИспользуя ключевые аргументы, код будет следующим:
from decimal import localcontext with localcontext(prec=42) as ctx: s = calculate_something() s = +sВозникает
TypeError, если kwargs предоставляет атрибут, которого не поддерживаетContext. Возникает либоTypeError, либоValueError, если kwargs предоставляет неверное значение для атрибута.Изменено в версии 3.11:
localcontext()теперь поддерживает установку атрибутов контекста с помощью ключевых аргументов.
Новые контексты также можно создать с помощью конструктора Context, описанного ниже. Кроме того, модуль предоставляет три предопределённых контекста:
-
class decimal.BasicContext -
Это стандартный контекст, определённый в спецификации общего десятичного арифметического. Точность установлена на девять. Округление установлено на
ROUND_HALF_UP. Все флаги сброшены. Все ловушки включены (обрабатываются как исключения), за исключениемInexact,RoundedиSubnormal.Из-за включения многих ловушек этот контекст полезен для отладки.
-
class decimal.ExtendedContext -
Это стандартный контекст, определённый в спецификации общего десятичного арифметического. Точность установлена на девять. Округление установлено на
ROUND_HALF_EVEN. Все флаги сброшены. Ни одна ловушка не включена (исключения не генерируются во время вычислений).Из-за выключения ловушек этот контекст полезен для приложений, которые предпочитают иметь результат
NaNилиInfinityвместо генерации исключений. Это позволяет приложению завершить работу в условиях, которые иначе приостановили бы программу.
-
class decimal.DefaultContext -
Этот контекст используется конструктором
Contextв качестве прототипа для новых контекстов. Изменение поля (например, точности) приводит к изменению значения по умолчанию для новых контекстов, созданных конструкторомContext.Этот контекст наиболее полезен в многопоточных средах. Изменение одного из полей до запуска потоков приводит к установлению системных значений по умолчанию. Изменять поля после запуска потоков не рекомендуется, так как это потребует синхронизации потоков для предотвращения гонок.
В однопоточных средах лучше вообще не использовать этот контекст. Вместо этого создавайте контексты явно, как описано ниже.
Значения по умолчанию:
Context.prec=28,Context.rounding=ROUND_HALF_EVEN, а также включены ловушки дляOverflow,InvalidOperationиDivisionByZero.
Помимо предоставленных трёх контекстов, новые контексты можно создавать с помощью конструктора Context.
-
class decimal.Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)
-
Создает новый контекст. Если поле не указано или равно
None, значения по умолчанию копируются изDefaultContext. Если поле flags не указано или равноNone, все флаги сбрасываются.prec — целое число в диапазоне [
1,MAX_PREC], определяющее точность арифметических операций в контексте.Опция rounding — одно из констант, перечисленных в разделе Способы округления.
Поля traps и flags перечисляют любые сигналы, которые нужно установить. В целом, новые контексты должны устанавливать только ловушки и оставлять флаги сброшенными.
Поля Emin и Emax — целые числа, определяющие допустимые пределы для экспонент. Emin должен находиться в диапазоне [
MIN_EMIN,0], Emax — в диапазоне [0,MAX_EMAX].Поле capitals принимает значение
0или1(значение по умолчанию). Если оно установлено в1, экспоненты выводятся с заглавной буквойE; в противном случае используется строчная букваe:Decimal('6.02e+23').Поле clamp принимает значение
0(значение по умолчанию) или1. Если оно установлено в1, показатель степениeэкземпляраDecimal, представимого в данном контексте, строго ограничен диапазономEmin - prec + 1 <= e <= Emax - prec + 1. Если clamp равно0, выполняется более слабое условие: корректированный показатель степени экземпляраDecimalне превышаетEmax. Когда clamp равно1, большая нормализованная величина, где это возможно, получит уменьшенный показатель степени и соответствующее количество нулей будет добавлено к её коэффициенту, чтобы соответствовать ограничениям показателя степени; это сохраняет значение числа, но теряет информацию о значащих заключительных нулях. Например:>>> Context(prec=6, Emax=999, clamp=1).create_decimal('1.23e999') Decimal('1.23000E+999')Значение clamp, равное
1, обеспечивает совместимость с фиксированными форматами десятичного обмена, определёнными в IEEE 754.Класс
Contextопределяет несколько общих методов, а также большое количество методов для выполнения арифметических операций непосредственно в заданном контексте. Кроме того, для каждого из методов классаDecimal, описанных выше (за исключением методовadjusted()иas_tuple()), существует соответствующий метод классаContext. Например, для экземпляраContextCи экземпляраDecimalx,C.exp(x)эквивалентноx.exp(context=C). Каждый метод классаContextпринимает целое число Python (экземплярint) в местах, где ожидается экземпляр Decimal.-
clear_flags() -
Сбрасывает все флаги в
0.
-
clear_traps() -
Сбрасывает все ловушки в
0.Добавлен в версии 3.3.
-
copy() -
Возвращает дубликат контекста.
-
copy_decimal(num) -
Возвращает копию экземпляра Decimal num.
-
create_decimal(num) -
Создает новый экземпляр Decimal из num, но использует self в качестве контекста. В отличие от конструктора
Decimal, точность контекста, метод округления, флаги и ловушки применяются к преобразованию.Это полезно, потому что константы часто задаются с большей точностью, чем требуется приложению. Другое преимущество состоит в том, что округление немедленно устраняет нежелательные эффекты от цифр, находящихся за пределами текущей точности. В следующем примере использование неокругленных входных данных означает, что добавление нуля к сумме может изменить результат:
>>> getcontext().prec = 3 >>> Decimal('3.4445') + Decimal('1.0023') Decimal('4.45') >>> Decimal('3.4445') + Decimal(0) + Decimal('1.0023') Decimal('4.44')Этот метод реализует операцию преобразования в число из спецификации IBM. Если аргументом является строка, то не допускаются ведущие или хвостовые пробелы или подчеркивания.
-
create_decimal_from_float(f) -
Создает новый экземпляр Decimal из числа с плавающей точкой f, но с округлением, используя self в качестве контекста. В отличие от метода класса
Decimal.from_float(), точность контекста, метод округления, флаги и ловушки применяются к преобразованию.>>> context = Context(prec=5, rounding=ROUND_DOWN) >>> context.create_decimal_from_float(math.pi) Decimal('3.1415') >>> context = Context(prec=5, traps=[Inexact]) >>> context.create_decimal_from_float(math.pi) Traceback (most recent call last): ... decimal.Inexact: NoneДобавлен в версии 3.1.
-
Etiny() -
Возвращает значение, равное
Emin - prec + 1, которое является минимальным значением показателя степени для результатов поднормализации. При возникновении недолива показатель степени устанавливается вEtiny.
-
Etop() -
Возвращает значение, равное
Emax - prec + 1.
Обычный подход к работе с десятичными числами — создание экземпляров
Decimal, а затем применение арифметических операций, которые выполняются в рамках текущего контекста для активного потока. Альтернативный подход — использование методов контекста для вычислений в определённом контексте. Эти методы аналогичны методам классаDecimalи здесь кратко перечислены.-
abs(x) -
Возвращает абсолютное значение x.
-
add(x, y) -
Возвращает сумму x и y.
-
canonical(x) -
Возвращает тот же объект Decimal x.
-
compare(x, y) -
Сравнивает x и y численно.
-
compare_signal(x, y) -
Сравнивает значения двух операндов численно.
-
compare_total(x, y) -
Сравнивает два операнда, используя их абстрактное представление.
-
compare_total_mag(x, y) -
Сравнивает два операнда, используя их абстрактное представление, игнорируя знак.
-
copy_abs(x) -
Возвращает копию x со знаком, установленным в 0.
-
copy_negate(x) -
Возвращает копию x с инвертированным знаком.
-
copy_sign(x, y) -
Копирует знак из y в x.
-
divide(x, y) -
Возвращает x, деленное на y.
-
divide_int(x, y) -
Возвращает x, деленное на y, с усечением до целого числа.
-
divmod(x, y) -
Делит два числа и возвращает целую часть результата.
-
exp(x) -
Возвращает
e ** x.
-
fma(x, y, z) -
Возвращает x, умноженное на y, плюс z.
-
is_canonical(x) -
Возвращает
Trueесли x канонично; в противном случае возвращаетFalse.
-
is_finite(x) -
Возвращает
Trueесли x конечно; в противном случае возвращаетFalse.
-
is_infinite(x) -
Возвращает
Trueесли x бесконечно; в противном случае возвращаетFalse.
-
-
is_nan(x) -
Возвращает
Trueесли x — qNaN или sNaN; в противном случае возвращаетFalse.
-
is_normal(x) -
Возвращает
Trueесли x — нормальное число; в противном случае возвращаетFalse.
-
is_qnan(x) -
Возвращает
Trueесли x — тихий NaN; в противном случае возвращаетFalse.
-
is_signed(x) -
Возвращает
Trueесли x отрицательное; в противном случае возвращаетFalse.
-
is_snan(x) -
Возвращает
Trueесли x — сигнализирующий NaN; в противном случае возвращаетFalse.
-
is_subnormal(x) -
Возвращает
Trueесли x — субнормальное; в противном случае возвращаетFalse.
-
is_zero(x) -
Возвращает
Trueесли x — ноль; в противном случае возвращаетFalse.
-
ln(x) -
Возвращает натуральный (по основанию e) логарифм x.
-
log10(x) -
Возвращает логарифм по основанию 10 от x.
-
logb(x) -
Возвращает показатель степени величины значащего разряда операнда.
-
logical_and(x, y) -
Применяет логическую операцию и к каждой паре цифр операндов.
-
logical_invert(x) -
Инвертирует все цифры в x.
-
logical_or(x, y) -
Применяет логическую операцию или к каждой паре цифр операндов.
-
logical_xor(x, y) -
Применяет логическую операцию исключающее или к каждой паре цифр операндов.
-
max(x, y) -
Сравнивает два значения численно и возвращает максимальное.
-
max_mag(x, y) -
Сравнивает значения численно, игнорируя знак.
-
min(x, y) -
Сравнивает два значения численно и возвращает минимальное.
-
min_mag(x, y) -
Сравнивает значения численно, игнорируя знак.
-
minus(x) -
Отрицание соответствует унарному префиксу минус в Python.
-
multiply(x, y) -
Возвращает произведение x и y.
-
next_minus(x) -
Возвращает наибольшее представимое число, меньшее чем x.
-
next_plus(x) -
Возвращает наименьшее представимое число, большее чем x.
-
next_toward(x, y) -
Возвращает число, ближайшее к x, в направлении к y.
-
normalize(x) -
Приводит x к его простейшей форме.
-
number_class(x) -
Возвращает индикатор класса x.
-
plus(x) -
Сложение соответствует унарному префиксу плюс в Python. Эта операция применяет точность и округление контекста, поэтому она не является тождественной операцией.
-
power(x, y, modulo=None) -
Возвращает
xв степениy, уменьшенное по модулюmoduloпри необходимости.С двумя аргументами вычисляет
x**y. Еслиxотрицательно, тоyдолжно быть целым. Результат будет неточен, еслиyцелое, результат конечен и может быть выражен точно в ‘precision’ цифрах. Используется режим округления контекста. Результаты всегда правильно округляются в версии Python.Decimal(0) ** Decimal(0)приводит кInvalidOperation, и еслиInvalidOperationне обрабатывается, то приводит кDecimal('NaN').Изменено в версии 3.3: Модуль C вычисляет
power()в терминах правильно округлённыхexp()иln()функций. Результат определён, но только «почти всегда правильно округлён».С тремя аргументами вычисляет
(x**y) % modulo. Для варианта с тремя аргументами следуют ограничения на аргументы:- все три аргумента должны быть целыми
-
yдолжно быть неотрицательным - по крайней мере один из
xилиyдолжен быть ненулевым -
moduloдолжно быть ненулевым и содержать не более ‘precision’ цифр
Значение, полученное от
Context.power(x, y, modulo), равно значению, которое было бы получено от вычисления(x**y) % moduloс неограниченной точностью, но вычисляется более эффективно. Показатель степени результата равен нулю, независимо от показателей степениx,yиmodulo. Результат всегда точный.
-
quantize(x, y) -
Возвращает значение, равное x (округлённое), имеющее показатель степени y.
-
radix() -
Просто возвращает 10, так как это Decimal, :)
-
remainder(x, y) -
Возвращает остаток от целочисленного деления.
Знак результата, если он не нулевой, совпадает со знаком исходного делимого.
-
remainder_near(x, y) -
Возвращает
x - y * n, где n — целое, ближайшее к точному значениюx / y(если результат 0, то его знак будет знаком x).
-
rotate(x, y) -
Возвращает повернутую копию x, на y позиций.
-
same_quantum(x, y) -
Возвращает
Trueесли два операнда имеют одинаковый показатель степени.
-
scaleb(x, y) -
Возвращает первый операнд после добавления ко второй величине её показателя.
-
shift(x, y) -
Возвращает сдвинутую копию x, на y позиций.
-
sqrt(x) -
Квадратный корень из неотрицательного числа с точностью контекста.
-
subtract(x, y) -
Возвращает разность между x и y.
-
to_eng_string(x) -
Преобразует в строку, используя инженерную нотацию, если нужен показатель степени.
Инженерная нотация имеет показатель степени, кратный 3. Это может оставить до 3 цифр слева от десятичной точки и может потребовать добавления одной или двух концевых нулей.
-
to_integral_exact(x) -
Округляет до целого числа.
-
to_sci_string(x) -
Преобразует число в строку, используя научную нотацию.
-
Константы
Константы в этом разделе актуальны только для модуля C. Они также включены в чистую версию Python для совместимости.
32-битный | 64-битный | |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
-
decimal.HAVE_THREADS -
Значение равно
True. Устарело, так как в Python всегда есть потоки.
Устарело начиная с версии 3.9.
-
decimal.HAVE_CONTEXTVAR -
Значение по умолчанию
True. Если Python используетconfigured using the --without-decimal-contextvar option, версия C использует локальную для потока, а не для сопрограммы, переменную контекста, и значение равноFalse. Это немного быстрее в некоторых сценариях вложенных контекстов.Добавлен в версии 3.8.3.
Режимы округления
-
decimal.ROUND_CEILING -
Округление вверх.
-
decimal.ROUND_DOWN -
Округление к нулю.
-
decimal.ROUND_FLOOR -
Округление вниз.
-
decimal.ROUND_HALF_DOWN -
Округление к ближайшему с предпочтением к нулю при равенстве.
-
decimal.ROUND_HALF_EVEN -
Округление к ближайшему с предпочтением к ближайшему четному числу при равенстве.
-
decimal.ROUND_HALF_UP -
Округление к ближайшему с предпочтением от нуля при равенстве.
-
decimal.ROUND_UP -
Округление от нуля.
-
decimal.ROUND_05UP -
Округление от нуля, если последняя цифра после округления к нулю была бы 0 или 5; в противном случае округление к нулю.
Сигналы
Сигналы представляют собой условия, возникающие во время вычислений. Каждый соответствует одному флагу контекста и одному разрешающему входу контекста для ловушки.
Флаг контекста устанавливается всякий раз, когда возникает условие. После вычисления флаги могут быть проверены для получения информации (например, чтобы определить, было ли вычисление точным). После проверки флагов обязательно очистите все флаги перед началом следующего вычисления.
Если для сигнала установлен разрешающий вход контекста для ловушки, то данное условие вызывает поднятие исключения Python. Например, если ловушка DivisionByZero установлена, то исключение DivisionByZero поднимается при обнаружении условия.
-
class decimal.Clamped -
Изменено значение показателя для соответствия ограничениям представления.
Обычно ограничение происходит, когда показатель выходит за пределы
EminиEmaxпределов контекста. Если возможно, показатель уменьшается для соответствия путем добавления нулей к коэффициенту.
-
class decimal.DecimalException -
Базовый класс для других сигналов и подкласс
ArithmeticError.
-
class decimal.DivisionByZero -
Сигнализирует деление ненулевого числа на ноль.
Может произойти при делении, модульном делении или при возведении числа в отрицательную степень. Если этот сигнал не ловится, возвращает
Infinityили-Infinityсо знаком, определяемым входами вычисления.
-
class decimal.Inexact -
Указывает, что произошло округление, и результат не точный.
Сигнализирует, когда во время округления были отброшены ненулевые цифры. Возвращается округленный результат. Сигнал или ловушка используются для определения случаев, когда результаты не точны.
-
class decimal.InvalidOperation -
Было выполнено недопустимое действие.
Указывает, что было запрошено действие, которое не имеет смысла. Если не ловится, возвращает
NaN. Возможные причины:Infinity - Infinity 0 * Infinity Infinity / Infinity x % 0 Infinity % x sqrt(-x) and x > 0 0 ** 0 x ** (non-integer) x ** Infinity
-
class decimal.Overflow -
Переполнение числового значения.
Указывает, что показатель больше
Context.Emaxпосле округления. Если не ловится, результат зависит от режима округления, либо втягивая к наибольшему представимому конечному числу, либо округляя наружу кInfinity. В любом случае,InexactиRoundedтакже сигнализируются.
-
class decimal.Rounded -
Произошло округление, хотя, возможно, информация не потеряна.
Сигнализируется всякий раз, когда округление отбрасывает цифры; даже если эти цифры нулевые (например, округление
5.00до5.0). Если не ловится, возвращает результат без изменений. Этот сигнал используется для обнаружения потери значимых цифр.
-
class decimal.Subnormal -
Показатель был меньше
Eminдо округления.Происходит, когда результат операции является субнормальным (показатель слишком мал). Если не ловится, возвращает результат без изменений.
-
class decimal.Underflow -
Числовой недолив с округленным к нулю результатом.
Происходит, когда субнормальный результат округляется до нуля.
InexactиSubnormalтакже сигнализируются.
-
class decimal.FloatOperation -
Включить более строгие семантики для смешивания чисел с плавающей запятой и 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, если этот сигнал не перехвачен. Обратите внимание, что спецификация общего десятичного арифметического вычисления не определяет поведение прямых сравнений; эти правила для сравнений, включающих NaN были взяты из стандарта IEEE 854 (см. Таблица 3 в разделе 5.7). Чтобы обеспечить строгую соответствие стандартам, используйте методы compare() и compare_signal().
Отрицательные нули могут возникнуть из вычислений, которые приводят к переполнению. Они сохраняют знак, который получился бы, если бы вычисления были выполнены с большей точностью. Поскольку их величина равна нулю, как положительные, так и отрицательные нули обрабатываются как равные, и их знак является информативным.
Помимо двух подписанных нулей, которые являются различными, но равными, существуют различные представления нуля с различной точностью, но эквивалентные по значению. Это требует некоторой привычки. Для глаза, привыкшего к нормализованным представлениям чисел с плавающей точкой, не сразу очевидно, что следующее вычисление возвращает значение, равное нулю:
>>> 1 / Decimal('Infinity')
Decimal('0E-1000026')
Работа с потоками
Функция getcontext() обращается к другому объекту Context для каждого потока. Наличие отдельных контекстов потоков означает, что потоки могут вносить изменения (например, getcontext().prec=10) без вмешательства в работу других потоков.
Аналогично, функция setcontext() автоматически назначает свой целевой объект текущему потоку.
Если функция setcontext() не вызывалась до getcontext(), то getcontext() автоматически создаст новый контекст для использования в текущем потоке.
Новый контекст копируется из прототипного контекста, называемого DefaultContext. Чтобы контролировать значения по умолчанию, чтобы каждый поток использовал одни и те же значения в приложении, непосредственно измените объект DefaultContext. Это следует сделать *до* запуска любых потоков, чтобы не возникло ситуации гонки между потоками, вызывающими getcontext(). Например:
# Set applicationwide defaults for all threads about to be launched DefaultContext.prec = 12 DefaultContext.rounding = ROUND_DOWN DefaultContext.traps = ExtendedContext.traps.copy() DefaultContext.traps[InvalidOperation] = 1 setcontext(DefaultContext) # Afterwards, the threads can be started t1.start() t2.start() t3.start() . . .
Рецепты
Ниже приведены несколько рецептов, которые служат вспомогательными функциями и демонстрируют способы работы с классом Decimal:
def moneyfmt(value, places=2, curr='', sep=',', dp='.',
pos='', neg='-', trailneg=''):
"""Convert Decimal to a money formatted string.
places: required number of places after the decimal point
curr: optional currency symbol before the sign (may be blank)
sep: optional grouping separator (comma, period, space, or blank)
dp: decimal point indicator (comma or period)
only specify as blank when places is zero
pos: optional sign for positive numbers: '+', space or blank
neg: optional sign for negative numbers: '-', '(', space or blank
trailneg:optional trailing minus indicator: '-', ')', space or blank
>>> d = Decimal('-1234567.8901')
>>> moneyfmt(d, curr='$')
'-$1,234,567.89'
>>> moneyfmt(d, places=0, sep='.', dp='', neg='', trailneg='-')
'1.234.568-'
>>> moneyfmt(d, curr='$', neg='(', trailneg=')')
'($1,234,567.89)'
>>> moneyfmt(Decimal(123456789), sep=' ')
'123 456 789.00'
>>> moneyfmt(Decimal('-0.02'), neg='<', trailneg='>')
'<0.02>'
"""
q = Decimal(10) ** -places # 2 places --> '0.01'
sign, digits, exp = value.quantize(q).as_tuple()
result = []
digits = list(map(str, digits))
build, next = result.append, digits.pop
if sign:
build(trailneg)
for i in range(places):
build(next() if digits else '0')
if places:
build(dp)
if not digits:
build('0')
i = 0
while digits:
build(next())
i += 1
if i == 3 and digits:
i = 0
build(sep)
build(curr)
build(neg if sign else pos)
return ''.join(reversed(result))
def pi():
"""Compute Pi to the current precision.
>>> print(pi())
3.141592653589793238462643383
"""
getcontext().prec += 2 # extra digits for intermediate steps
three = Decimal(3) # substitute "three=3.0" for regular floats
lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
while s != lasts:
lasts = s
n, na = n+na, na+8
d, da = d+da, da+32
t = (t * n) / d
s += t
getcontext().prec -= 2
return +s # unary plus applies the new precision
def exp(x):
"""Return e raised to the power of x. Result type matches input type.
>>> print(exp(Decimal(1)))
2.718281828459045235360287471
>>> print(exp(Decimal(2)))
7.389056098930650227230427461
>>> print(exp(2.0))
7.38905609893
>>> print(exp(2+0j))
(7.38905609893+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num = 0, 0, 1, 1, 1
while s != lasts:
lasts = s
i += 1
fact *= i
num *= x
s += num / fact
getcontext().prec -= 2
return +s
def cos(x):
"""Return the cosine of x as measured in radians.
The Taylor series approximation works best for a small value of x.
For larger values, first compute x = x % (2 * pi).
>>> print(cos(Decimal('0.5')))
0.8775825618903727161162815826
>>> print(cos(0.5))
0.87758256189
>>> print(cos(0.5+0j))
(0.87758256189+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num, sign = 0, 0, 1, 1, 1, 1
while s != lasts:
lasts = s
i += 2
fact *= i * (i-1)
num *= x * x
sign *= -1
s += num / fact * sign
getcontext().prec -= 2
return +s
def sin(x):
"""Return the sine of x as measured in radians.
The Taylor series approximation works best for a small value of x.
For larger values, first compute x = x % (2 * pi).
>>> print(sin(Decimal('0.5')))
0.4794255386042030002732879352
>>> print(sin(0.5))
0.479425538604
>>> print(sin(0.5+0j))
(0.479425538604+0j)
"""
getcontext().prec += 2
i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1
while s != lasts:
lasts = s
i += 2
fact *= i * (i-1)
num *= x * x
sign *= -1
s += num / fact * sign
getcontext().prec -= 2
return +s
Часто задаваемые вопросы о Decimal
В. Ввод 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 версии 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 >>> >>> # 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–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/library/decimal.html