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 предпочтительнее в приложениях, связанных с учётом, которые имеют строгие инварианты равенства. - Модуль 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.
Для каждого сигнала есть флаг и обработчик сигнала. Когда возникает сигнал, его флаг устанавливается в 1, затем, если обработчик сигнала установлен в 1, генерируется исключение. Флаги сохраняются, поэтому пользователю нужно сбросить их перед мониторингом вычисления.
См. также
- Спецификация общей десятичной арифметики 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 показывает, что рациональное приближение к Pi было округлено (цифры за пределами точности контекста были отброшены) и что результат неточный (некоторые отброшенные цифры были отличны от нуля).
Индивидуальные обработчики сигналов устанавливаются с помощью словаря в поле 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. Применимы все обычные математические операции и специальные методы. Аналогично, объекты Decimal можно копировать, сериализовать, выводить на печать, использовать в качестве ключей словарей, элементов множеств, сравнивать, сортировать и приводить к другому типу (например,floatилиint).Существуют некоторые небольшие различия между арифметическими операциями с объектами Decimal и арифметическими операциями с целыми числами и числами с плавающей точкой. При применении оператора остатка
%к объектам Decimal знак результата — это знак делимого, а не делителя:>>> (-7) % 4 1 >>> Decimal(-7) % Decimal(4) Decimal('-3')Оператор целочисленного деления
//ведёт себя аналогично, возвращая целую часть истинного частного (отбрасывая к нулю), а не его целую часть, чтобы сохранить обычное тождествоx == (x // y) * y + x % y:>>> -7 // 4 -2 >>> Decimal(-7) // Decimal(4) Decimal('-1')Операторы
%и//реализуют операцииremainderиdivide-integer(соответственно), как описано в спецификации.Объекты Decimal обычно нельзя комбинировать с числами с плавающей точкой или экземплярами
fractions.Fractionв арифметических операциях: попытка добавитьDecimalкfloat, например, вызоветTypeError. Однако можно использовать операторы сравнения Python для сравнения экземпляраDecimalxс другим числомy. Это позволяет избежать путаницы при сравнении на равенство чисел разных типов.Изменено в версии 3.2: Теперь полностью поддерживаются сравнения смешанного типа между экземплярами
Decimalи другими числовыми типами.Помимо стандартных числовых свойств, объекты десятичной плавающей точки также имеют ряд специализированных методов:
-
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')
-
from_float(f) -
Метод класса, преобразующий число с плавающей точкой в десятичное число точно.
Обратите внимание, что
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_nan() -
Возвращает
True, если аргумент является (тихим или сигнализирующим) NaN, иFalseв противном случае.
-
is_normal(context=None) -
Возвращает
True, если аргумент является нормальным конечным числом. ВозвращаетFalse, если аргумент равен нулю, поднормализованному, бесконечному или NaN.
-
is_signed() -
Возвращает
True, если аргумент имеет отрицательный знак, иFalseв противном случае. Обратите внимание, что нули и NaN могут иметь знаки.
-
is_subnormal(context=None) -
Возвращает
True, если аргумент является поднормализованным, иFalseв противном случае.
-
is_zero() -
Возвращает
True, если аргумент равен (положительному или отрицательному) нулю, иFalseв противном случае.
-
ln(context=None) -
Возвращает натуральный (с основанием e) логарифм операнда. Результат правильно округляется с помощью режима округления
ROUND_HALF_EVEN.
-
log10(context=None) -
Возвращает десятичный логарифм операнда. Результат правильно округляется с помощью режима округления
ROUND_HALF_EVEN.
-
logb(context=None) -
Для ненулевого числа возвращает скорректированный показатель степени своего операнда как экземпляр
Decimal. Если операнд равен нулю, возвращаетсяDecimal('-Infinity'), и поднимается флагDivisionByZero. Если операнд равен бесконечности, возвращаетсяDecimal('Infinity').
-
logical_and(other, context=None) -
logical_and()- это логическая операция, которая принимает два логических операнда (см. Логические операнды). Результат представляет собой цифровойandдвух операндов.
-
logical_invert(context=None) -
logical_invert()- это логическая операция. Результат представляет собой цифровой инвертированный операнд.
-
logical_or(other, context=None) -
logical_or()- это логическая операция, которая принимает два логических операнда (см. Логические операнды). Результат представляет собой цифровойorдвух операндов.
-
logical_xor(other, context=None) -
logical_xor()- это логическая операция, которая принимает два логических операнда (см. Логические операнды). Результат представляет собой цифровой исключающий или двух операндов.
-
max(other, context=None) -
Подобно
max(self, other), за исключением того, что правило округления контекста применяется перед возвращением, и что значенияNaNлибо сигнализируются, либо игнорируются (в зависимости от контекста и являются ли они сигнализирующими или тихими).
-
max_mag(other, context=None) -
Аналогично методу
max(), но сравнение выполняется с использованием абсолютных значений операндов.
-
min(other, context=None) -
Подобно
min(self, other), за исключением того, что правило округления контекста применяется перед возвращением, и что значенияNaNлибо сигнализируются, либо игнорируются (в зависимости от контекста и являются ли они сигнализирующими или тихими).
-
min_mag(other, context=None) -
Аналогично методу
min(), но сравнение выполняется с использованием абсолютных значений операндов.
-
next_minus(context=None) -
Возвращает наибольшее число, представимое в заданном контексте (или в контексте текущей нити, если контекст не задан), меньшее, чем заданный операнд.
-
next_plus(context=None) -
Возвращает наименьшее число, представимое в заданном контексте (или в контексте текущей нити, если контекст не задан), большее, чем заданный операнд.
-
next_toward(other, context=None) -
Если два операнда не равны, возвращает число, наиболее близкое к первому операнду в направлении второго операнда. Если оба операнда численно равны, возвращает копию первого операнда со знаком, установленным таким же, как знак второго операнда.
-
-
normalize(context=None) -
Нормализуйте число, удалив справа все нули и преобразовав любой результат, равный
Decimal('0')кDecimal('0e0'). Используется для получения канонических значений атрибутов класса эквивалентности. Например,Decimal('32.100')иDecimal('0.321000e+2')оба нормализуются к эквивалентному значениюDecimal('32.1').
-
number_class(context=None) -
Возвращает строку, описывающую класс операнда. Возвращаемое значение — одна из следующих десяти строк.
-
"-Infinity", указывающее, что операнд равен отрицательной бесконечности. -
"-Normal", указывающее, что операнд — отрицательное нормальное число. -
"-Subnormal", указывающее, что операнд отрицательный и субнормальный. -
"-Zero", указывающее, что операнд — отрицательный ноль. -
"+Zero", указывающее, что операнд — положительный ноль. -
"+Subnormal", указывающее, что операнд положительный и субнормальный. -
"+Normal", указывающее, что операнд — положительное нормальное число. -
"+Infinity", указывающее, что операнд равен положительной бесконечности. -
"NaN", указывающее, что операнд — тихий NaN (не число). -
"sNaN", указывающее, что операнд — сигнализирующий NaN.
-
-
quantize(exp, rounding=None, context=None) -
Возвращает значение, равное первому операнду после округления и с экспонентой второго операнда.
>>> Decimal('1.41421356').quantize(Decimal('1.000')) Decimal('1.414')В отличие от других операций, если длина коэффициента после операции quantize будет больше precision, то сигнализируется
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. Если ни один параметр не задан, используется режим округления текущего контекста.
-
Логические операнды
Методы logical_and(), logical_invert(), logical_or(), и logical_xor() ожидают в качестве аргументов логические операнды. Логический операнд — это экземпляр Decimal, у которого экспонента и знак равны нулю, а все цифры равны либо 0, либо 1.
Объекты контекста
Контексты — это среды для арифметических операций. Они управляют точностью, устанавливают правила округления, определяют, какие сигналы обрабатываются как исключения и ограничивают диапазон для показателей степени.
В каждом потоке есть свой текущий контекст, к которому можно получить доступ или изменить его с помощью функций getcontext() и setcontext():
-
decimal.getcontext() -
Возвращает текущий контекст для активного потока.
-
decimal.setcontext(c) -
Устанавливает текущий контекст для активного потока в c.
Вы также можете использовать оператор with и функцию localcontext() для временного изменения активного контекста.
-
decimal.localcontext(ctx=None) -
Возвращает менеджер контекста, который установит текущий контекст для активного потока в копию ctx при входе в оператор with и восстановит предыдущий контекст при выходе из оператора with. Если контекст не указан, используется копия текущего контекста.
Например, следующий код устанавливает текущую десятичную точность до 42 знаков, выполняет вычисление и затем автоматически восстанавливает предыдущий контекст:
from decimal import localcontext with localcontext() as ctx: ctx.prec = 42 # Perform a high precision calculation s = calculate_something() s = +s # Round the final result back to the default precision
Новые контексты также можно создать, используя конструктор Context, описанный ниже. Кроме того, модуль предоставляет три предварительно созданных контекста:
-
class decimal.BasicContext -
Это стандартный контекст, определенный в Спецификации общей десятичной арифметики. Точность установлена в девять. Округление установлено в
ROUND_HALF_UP. Все флаги сброшены. Все ловушки включены (обрабатываются как исключения), за исключениемInexact,RoundedиSubnormal.Поскольку многие ловушки включены, этот контекст полезен для отладки.
-
class decimal.ExtendedContext -
Это стандартный контекст, определенный в Спецификации общей десятичной арифметики. Точность установлена в девять. Округление установлено в
ROUND_HALF_EVEN. Все флаги сброшены. Никакие ловушки не включены (так что исключения не генерируются во время вычислений).Поскольку ловушки отключены, этот контекст полезен для приложений, которые предпочитают иметь значение результата
NaNилиInfinityвместо повышения исключений. Это позволяет приложению завершить выполнение в присутствии условий, которые в противном случае остановили бы программу.
-
class decimal.DefaultContext -
Этот контекст используется конструктором
Contextв качестве прототипа для новых контекстов. Изменение поля (например, точности) влияет на значение по умолчанию для новых контекстов, созданных конструкторомContext.Этот контекст наиболее полезен в многопоточных средах. Изменение одного из полей перед запуском потоков приводит к установлению системных значений по умолчанию. Изменение полей после запуска потоков не рекомендуется, так как это потребует синхронизации потоков для предотвращения гонок.
В однопоточных средах лучше вообще не использовать этот контекст. Вместо этого просто создавайте контексты явно, как описано ниже.
Значения по умолчанию —
prec=28,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 скомпилирован--without-decimal-contextvar, версия C использует контекст уровня потока вместо контекста уровня корутины, и значение равноFalse. Это немного быстрее в некоторых сценариях вложенных контекстов.
Добавлена в версии 3.9: обратно перенесена в 3.7 и 3.8.
Режимы округления
-
decimal.ROUND_CEILING -
Округление в сторону
Infinity.
-
decimal.ROUND_DOWN -
Округление к нулю.
-
decimal.ROUND_FLOOR -
Округление в сторону
-Infinity.
-
decimal.ROUND_HALF_DOWN -
Округление к ближайшему с ties, направленным к нулю.
-
decimal.ROUND_HALF_EVEN -
Округление к ближайшему с ties к ближайшему четному целому.
-
decimal.ROUND_HALF_UP -
Округление к ближайшему с ties, удаляющимся от нуля.
-
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 -
Переполнение.
Указывает, что порядок величины больше
Emaxпосле округления. Если не перехвачена, результат зависит от режима округления, либо втягивается к наибольшему представимому конечному числу, либо округляется наружу доInfinity. В любом случае,InexactиRoundedтакже сигнализируются.
-
class decimal.Rounded -
Произошло округление, хотя, возможно, никакая информация не была потеряна.
Сигнализируется всякий раз, когда округление отбрасывает цифры; даже если эти цифры равны нулю (например, при округлении
5.00до5.0). Если не перехвачена, возвращает результат без изменений. Этот сигнал используется для обнаружения потери значимых цифр.
-
class decimal.Subnormal -
Порядок величины был ниже
Eminдо округления.Возникает, когда результат операции является субнормальным (порядок величины слишком мал). Если не перехвачена, возвращает результат без изменений.
-
class decimal.Underflow -
Числовое подпотоление с результатом, округлённым до нуля.
Возникает, когда субнормальный результат приводится к нулю путём округления.
InexactиSubnormalтакже сигнализируются.
-
class decimal.FloatOperation -
Включает более строгие семантики для смешения чисел с плавающей запятой и десятичных чисел.
Если сигнал не перехвачен (по умолчанию), смешивание чисел с плавающей запятой и десятичных чисел разрешено в конструкторе
Decimal,create_decimal()и всех операторах сравнения. Как преобразование, так и сравнения являются точными. Любое смешанное действие записывается безмолвно путём установкиFloatOperationво флагах контекста. Явные преобразования с помощьюfrom_float()илиcreate_decimal_from_float()не устанавливают флаг.В противном случае (сигнал перехвачен), только сравнения на равенство и явные преобразования беззвучны. Все остальные смешанные операции вызывают
FloatOperation.
Следующая таблица обобщает иерархию сигналов:
exceptions.ArithmeticError(exceptions.Exception)
DecimalException
Clamped
DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
Inexact
Overflow(Inexact, Rounded)
Underflow(Inexact, Rounded, Subnormal)
InvalidOperation
Rounded
Subnormal
FloatOperation(DecimalException, exceptions.TypeError)
Заметки по числам с плавающей точкой
Устранение ошибки округления с повышенной точностью
Использование десятичных чисел с плавающей точкой устраняет ошибку представления десятичных знаков (что позволяет точно представлять 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')]
В. Некоторые десятичные значения всегда отображаются с экспоненциальной записью. Есть ли способ получить представление без экспоненты?
О. Для некоторых значений экспоненциальная запись — единственный способ выразить число значащих цифр в коэффициенте. Например, выражение 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 требует некоторой осторожности.
Самый простой подход для тестирования арифметики bignum — использовать максимальное значение для prec также 2:
>>> setcontext(Context(prec=MAX_PREC, Emax=MAX_EMAX, Emin=MIN_EMIN))
>>> x = Decimal(2) ** 256
>>> x / 128
Decimal('904625697166532776746648320380374280103671755200316906558262375061821325312')
Для приближенных результатов MAX_PREC слишком велико на 64-битных платформах, и доступной памяти будет недостаточно:
>>> Decimal(1) / 3 Traceback (most recent call last): File "<stdin>", line 1, in <module> MemoryError
На системах с перераспределением памяти (например, Linux) более сложный подход заключается в настройке prec в соответствии с объемом доступной оперативной памяти. Предположим, что у вас 8 ГБ оперативной памяти и ожидается 10 одновременных операндов, используя максимум 500 МБ каждый:
>>> import sys >>> >>> # Maximum number of digits for a single operand using 500MB in 8-byte words >>> # with 19 digits per word (4-byte and 9 digits for the 32-bit build): >>> maxdigits = 19 * ((500 * 1024**2) // 8) >>> >>> # Check that this works: >>> c = Context(prec=maxdigits, Emax=MAX_EMAX, Emin=MIN_EMIN) >>> c.traps[Inexact] = True >>> setcontext(c) >>> >>> # Fill the available precision with nines: >>> x = Decimal(0).logical_invert() * 9 >>> sys.getsizeof(x) 524288112 >>> x + 2 Traceback (most recent call last): File "<stdin>", line 1, in <module> decimal.Inexact: [<class 'decimal.Inexact'>]
В общем случае (и особенно на системах без перераспределения памяти) рекомендуется устанавливать даже более узкие границы и устанавливать ловушку Inexact, если ожидается, что все вычисления будут точными.
-
1 -
New in version 3.3.
-
2 -
Изменено в версии 3.9: Этот подход теперь работает для всех точных результатов, кроме нецелых степеней.
© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.9/library/decimal.html