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')
Для 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'.Если 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. Однако для сравнения экземпляраDecimalxс другим числомyможно использовать операторы сравнения Python. Это позволяет избежать неоднозначных результатов при сравнении на равенство чисел разных типов.Изменено в версии 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.>>> Decimal.from_float(0.1) Decimal('0.1000000000000000055511151231257827021181583404541015625') >>> Decimal.from_float(float('nan')) Decimal('NaN') >>> Decimal.from_float(float('inf')) Decimal('Infinity') >>> Decimal.from_float(float('-inf')) Decimal('-Infinity')Добавлено в версии 3.1.
-
fma(other, third, context=None) -
Умножение с накоплением без промежуточного округления. Возвращает self*other+third без округления промежуточного произведения self*other.
>>> Decimal(2).fma(3, 5) Decimal('11')
-
is_canonical() -
Возвращает
True, если аргумент канонический, иFalseв противном случае. В настоящее время экземплярDecimalвсегда канонический, поэтому эта операция всегда возвращаетTrue.
-
is_finite() -
Возвращает
True, если аргумент является конечным числом, иFalse, если аргумент — бесконечность или NaN.
-
is_infinite() -
Возвращает
True, если аргумент — положительная или отрицательная бесконечность, иFalseв противном случае.
-
is_normal(context=None) -
Возвращает
True, если аргумент является нормальным конечным числом. ВозвращаетFalse, если аргумент равен нулю, является субнормальным числом, бесконечностью или NaN.
-
is_signed() -
Возвращает
True, если аргумент имеет отрицательный знак, иFalseв противном случае. Обратите внимание, что нули и NaN могут иметь знак.
-
is_subnormal(context=None) -
Возвращает
True, если аргумент является субнормальным числом, иFalseв противном случае.
-
is_zero() -
Возвращает
True, если аргумент равен (положительному или отрицательному) нулю, иFalseв противном случае.
-
ln(context=None) -
Возвращает натуральный логарифм операнда (по основанию e). Результат корректно округляется с использованием режима округления
ROUND_HALF_EVEN.
-
log10(context=None) -
Возвращает десятичный логарифм операнда. Результат корректно округляется с использованием режима округления
ROUND_HALF_EVEN.
-
logb(context=None) -
Для ненулевого числа возвращает скорректированный показатель степени операнда в виде экземпляра
Decimal. Если операнд равен нулю, возвращаетсяDecimal('-Infinity')и устанавливается флагDivisionByZero. Если операнд — бесконечность, возвращаетсяDecimal('Infinity').
-
logical_and(other, context=None) -
logical_and()— логическая операция с двумя логическими операндами (см. раздел Логические операнды). Результат представляет собой поразрядную операциюandнад двумя операндами.
-
logical_invert(context=None) -
logical_invert()— логическая операция. Результат представляет собой поразрядную инверсию операнда.
-
logical_or(other, context=None) -
logical_or()— логическая операция с двумя логическими операндами (см. раздел Логические операнды). Результат представляет собой поразрядную операциюorнад двумя операндами.
-
logical_xor(other, context=None) -
logical_xor()— логическая операция с двумя логическими операндами (см. раздел Логические операнды). Результат представляет собой поразрядную операцию исключающего ИЛИ над двумя операндами.
-
max(other, context=None) -
Аналогичен
max(self, other), за исключением того, что перед возвратом результата применяется правило округления контекста, а значенияNaNлибо вызывают сигнал, либо игнорируются (в зависимости от контекста и от того, являются ли они сигнальными или тихими).
-
max_mag(other, context=None) -
Подобен методу
max(), но сравнение выполняется по абсолютным значениям операндов.
-
min(other, context=None) -
Аналогичен
min(self, other), за исключением того, что перед возвратом результата применяется правило округления контекста, а значенияNaNлибо вызывают сигнал, либо игнорируются (в зависимости от контекста и от того, являются ли они сигнальными или тихими).
-
min_mag(other, context=None) -
Подобен методу
min(), но сравнение выполняется по абсолютным значениям операндов.
-
next_minus(context=None) -
Возвращает наибольшее число, представимое в заданном контексте (или в контексте текущего потока, если контекст не задан), которое меньше заданного операнда.
-
next_plus(context=None) -
Возвращает наименьшее число, представимое в заданном контексте (или в контексте текущего потока, если контекст не задан), которое больше заданного операнда.
-
next_toward(other, context=None) -
Если операнды не равны, возвращает число, ближайшее к первому операнду в направлении второго операнда. Если оба операнда численно равны, возвращает копию первого операнда со знаком, совпадающим со знаком второго операнда.
-
normalize(context=None) -
Используется для получения канонических значений класса эквивалентности в текущем или указанном контексте.
Семантика этого метода совпадает с семантикой унарного плюса, за исключением того, что конечный результат приводится к простейшей форме: все конечные нули удаляются, а знак сохраняется. То есть пока коэффициент ненулевой и кратен десяти, он делится на десять, а показатель степени увеличивается на 1. В противном случае (если коэффициент равен нулю) показатель степени устанавливается в 0. Во всех случаях знак не меняется.
Например,
Decimal('32.100')иDecimal('0.321000e+2')нормализуются до эквивалентного значенияDecimal('32.1').Обратите внимание, что округление выполняется до приведения к простейшей форме.
В последних версиях спецификации эта операция также называется
reduce.
-
number_class(context=None) -
Возвращает строку, описывающую класс операнда. Возвращаемое значение — одна из следующих десяти строк.
-
"-Infinity"— операнд является отрицательной бесконечностью. -
"-Normal"— операнд является отрицательным нормальным числом. -
"-Subnormal"— операнд является отрицательным субнормальным числом. -
"-Zero"— операнд является отрицательным нулём. -
"+Zero"— операнд является положительным нулём. -
"+Subnormal"— операнд является положительным субнормальным числом. -
"+Normal"— операнд является положительным нормальным числом. -
"+Infinity"— операнд является положительной бесконечностью. -
"NaN"— операнд является тихим NaN (не числом). -
"sNaN"— операнд является сигнальным NaN.
-
-
quantize(exp, rounding=None, context=None) -
Возвращает значение, равное первому операнду после округления, с показателем степени второго операнда.
>>> Decimal('1.41421356').quantize(Decimal('1.000')) Decimal('1.414')В отличие от других операций, если после операции quantize длина коэффициента превысит точность, возникает сигнал
InvalidOperation. Это гарантирует, что при отсутствии ошибки показатель степени после квантования всегда будет равен показателю степени правого операнда.Кроме того, в отличие от других операций, quantize никогда не вызывает сигнал Underflow, даже если результат является субнормальным и неточным.
Если показатель степени второго операнда больше показателя степени первого, может потребоваться округление. В этом случае режим округления определяется аргументом
rounding, если он задан, иначе аргументомcontext; если не задан ни один из них, используется режим округления контекста текущего потока.Возвращается ошибка, если показатель степени результата больше
Emaxили меньшеEtiny().
-
radix() -
Возвращает
Decimal(10)— основание системы счисления, в которой классDecimalвыполняет всю арифметику. Метод включён для совместимости со спецификацией.
-
remainder_near(other, context=None) -
Возвращает остаток от деления self на other. Этот метод отличается от
self % otherтем, что знак остатка выбирается так, чтобы минимизировать его абсолютное значение. Точнее, возвращаемое значение равноself - n * other, гдеn— целое число, ближайшее к точному значениюself / other; если ближайших целых два, выбирается чётное.Если результат равен нулю, его знак совпадает со знаком self.
>>> Decimal(18).remainder_near(Decimal(10)) Decimal('-2') >>> Decimal(25).remainder_near(Decimal(10)) Decimal('5') >>> Decimal(35).remainder_near(Decimal(10)) Decimal('-5')
-
rotate(other, context=None) -
Возвращает результат циклического сдвига цифр первого операнда на величину, заданную вторым операндом. Второй операнд должен быть целым числом в диапазоне от -precision до precision. Абсолютное значение второго операнда задаёт количество позиций сдвига. Если второй операнд положителен, сдвиг выполняется влево; в противном случае — вправо. При необходимости коэффициент первого операнда дополняется слева нулями до длины precision. Знак и показатель степени первого операнда не меняются.
-
same_quantum(other, context=None) -
Проверяет, совпадают ли показатели степени у self и other или являются ли оба значения
NaN.На эту операцию не влияет контекст; она не вызывает сигналов: флаги не меняются и округление не выполняется. Исключение: версия на C может вызвать InvalidOperation, если второй операнд невозможно преобразовать точно.
-
scaleb(other, context=None) -
Возвращает первый операнд с показателем степени, скорректированным на значение второго операнда. Иными словами, возвращает первый операнд, умноженный на
10**other. Второй операнд должен быть целым числом.
-
shift(other, context=None) -
Возвращает результат сдвига цифр первого операнда на величину, заданную вторым операндом. Второй операнд должен быть целым числом в диапазоне от -precision до precision. Абсолютное значение второго операнда задаёт количество позиций сдвига. Если второй операнд положителен, сдвиг выполняется влево; в противном случае — вправо. В коэффициент при сдвиге добавляются нули. Знак и показатель степени первого операнда не меняются.
-
sqrt(context=None) -
Возвращает квадратный корень из аргумента с полной точностью.
-
-
to_eng_string(context=None) -
Преобразует в строку, используя инженерную нотацию, если требуется показатель степени.
В инженерной нотации показатель степени кратен 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 используется для задания атрибутов нового контекста.
Например, следующий код устанавливает текущую точность Decimal равной 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. Кроме того, модуль предоставляет три предварительно созданных контекста:
-
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) -
Создаёт новый экземпляр 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() автоматически назначает целевой контекст текущему потоку.
Если функция 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 версии модуля 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–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/library/decimal.html