decimal — Арифметика десятичных чисел с фиксированной и плавающей точкой
Новая в версии 2.4.
Модуль 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.
Для каждого сигнала есть флаг и обработчик сигнала. При возникновении сигнала его флаг устанавливается в единицу, а затем, если обработчик сигнала установлен в единицу, возникает исключение. Флаги сохраняются, поэтому пользователю необходимо сбросить их перед мониторингом вычислений.
См. также
- Спецификация IBM по общей арифметике десятичных чисел, Спецификация общей арифметики десятичных чисел.
1. Быстрый старт
Обычно для работы с десятичными числами необходимо импортировать модуль, просмотреть текущий контекст с помощью getcontext() и, при необходимости, установить новые значения для точности, округления или включённых обработчиков сигналов:
>>> from decimal import *
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
capitals=1, 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.41421356237')
>>> Decimal(2) ** Decimal('0.5')
Decimal('1.414213562373095048801688724')
>>> Decimal('NaN')
Decimal('NaN')
>>> Decimal('-Infinity')
Decimal('-Infinity')
Значимость нового 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')
Десятичные числа хорошо взаимодействуют со значительной частью остальной части Python. Вот небольшой пример использования десятичных чисел с плавающей точкой:
>>> data = 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) # round() first converts to binary floating point
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=-999999999, Emax=999999999,
capitals=1, 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=-999999999, Emax=999999999,
capitals=1, flags=[Rounded, Inexact], 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.
2. Объекты Decimal
-
class decimal.Decimal([value[, context]]) -
Создайте новый объект
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
Если value — строка Unicode, допускаются и другие десятичные цифры Unicode, где
digitуказано выше. К ним относятся десятичные цифры из различных других алфавитов (например, арабские и деванагари цифры), а также полноширинные цифры отu'\uff10'доu'\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неизменяемы.Изменено в версии 2.6: при создании объекта Decimal из строки разрешаются начальные и конечные пробелы.
Изменено в версии 2.7: Аргументом конструктора теперь может быть экземпляр
float.Объекты Decimal с плавающей точкой имеют много свойств, общих с другими встроенными числовыми типами, такими как
floatиint. Применяются все обычные математические операции и специальные методы. Аналогично, объекты Decimal можно копировать, сохранять в виде pickle, выводить на печать, использовать в качестве ключей словарей, элементов множеств, сравнивать, сортировать и приводить к другому типу (например,floatилиlong).Существуют некоторые небольшие различия между арифметическими операциями над объектами 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 обычно нельзя комбинировать с числами с плавающей точкой в арифметических операциях: попытка сложить
Decimalиfloat, например, вызоветTypeError. Есть одно исключение из этого правила: можно использовать операторы сравнения Python для сравнения экземпляраfloatxс экземпляромDecimaly. Без этого исключения сравнения междуDecimalиfloatэкземплярами будут следовать общим правилам сравнения объектов разных типов, описанным в разделе «Выражения» руководства по справочной информации, что приведет к путанице.Изменено в версии 2.7: Сравнение экземпляра
floatxи экземпляраDecimalyтеперь возвращает результат, основанный на значенияхxиy. В предыдущих версияхx < yвозвращался один и тот же (произвольный) результат для любого экземпляраDecimalxи любого экземпляраfloaty.В дополнение к стандартным числовым свойствам, объекты с плавающей точкой Decimal также имеют ряд специализированных методов:
-
adjusted() -
Возвращает скорректированный показатель степени после сдвига вправо самых правых цифр коэфициента до тех пор, пока не останется только ведущая цифра:
Decimal('321e+5').adjusted()возвращает семь. Используется для определения позиции самой значимой цифры относительно десятичной точки.
-
as_tuple() -
Возвращает представление числа в виде именованного кортежа:
DecimalTuple(sign, digits, exponent).Изменено в версии 2.6: Использование именованного кортежа.
-
canonical() -
Возвращает каноническое представление аргумента. В настоящее время представление экземпляра
Decimalвсегда каноническое, поэтому эта операция возвращает свой аргумент без изменений.Добавлен в версии 2.6.
-
compare(other[, context]) -
Сравнение значений двух экземпляров Decimal. Эта операция ведет себя так же, как обычный метод сравнения
__cmp__(), за исключением того, что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]) -
Эта операция идентична методу
compare(), за исключением того, что все NaN сигнализируют. То есть, если ни один из операндов не является сигнализирующим NaN, любой тихий операнд NaN обрабатывается так, как будто он является сигнализирующим NaN.Добавлен в версии 2.6.
-
compare_total(other) -
Сравнение двух операндов, используя их абстрактное представление, а не их числовое значение. Аналогично методу
compare(), но результат дает полное упорядочение экземпляровDecimal. Два экземпляраDecimalс одинаковым числовым значением, но различным представлением, в этом порядке сравниваются неравно:>>> Decimal('12.0').compare_total(Decimal('12')) Decimal('-1')Тихие и сигнализирующие NaN также включены в общее упорядочение. Результатом этой функции является
Decimal('0')если оба операнда имеют одинаковое представление,Decimal('-1')если первый операнд ниже во общем порядке, чем второй, иDecimal('1')если первый операнд выше в общем порядке, чем второй операнд. Подробности общего порядка см. в спецификации.Добавлен в версии 2.6.
-
compare_total_mag(other) -
Сравнение двух операндов по их абстрактному представлению, как в
compare_total(), но игнорируя знак каждого операнда.x.compare_total_mag(y)эквивалентноx.copy_abs().compare_total(y.copy_abs()).Добавлен в версии 2.6.
-
conjugate() -
Просто возвращает self, этот метод предназначен только для соответствия спецификации Decimal.
Добавлен в версии 2.6.
-
-
copy_abs() -
Возвращает абсолютное значение аргумента. Эта операция не зависит от контекста и является бесшумной: флаги не изменяются, и округление не выполняется.
Новое в версии 2.6.
-
copy_negate() -
Возвращает отрицание аргумента. Эта операция не зависит от контекста и является бесшумной: флаги не изменяются, и округление не выполняется.
Новое в версии 2.6.
-
copy_sign(other) -
Возвращает копию первого операнда со знаком, установленным таким же, как знак второго операнда. Например:
>>> Decimal('2.3').copy_sign(Decimal('-1.5')) Decimal('-2.3')Эта операция не зависит от контекста и является бесшумной: флаги не изменяются, и округление не выполняется.
Новое в версии 2.6.
-
exp([context]) -
Возвращает значение экспоненциальной функции (натуральный логарифм)
e**xдля заданного числа. Результат правильно округляется с использованиемROUND_HALF_EVENрежима округления.>>> Decimal(1).exp() Decimal('2.718281828459045235360287471') >>> Decimal(321).exp() Decimal('2.561702493119680037517373933E+139')Новое в версии 2.6.
-
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')Новое в версии 2.7.
-
fma(other, third[, context]) -
Объединённое умножение и сложение. Возвращает self*other+third без округления промежуточного произведения self*other.
>>> Decimal(2).fma(3, 5) Decimal('11')Новое в версии 2.6.
-
is_canonical() -
Возвращает
True, если аргумент является каноническим, иFalseв противном случае. В настоящее время экземплярDecimalвсегда является каноническим, поэтому эта операция всегда возвращаетTrue.Новое в версии 2.6.
-
is_finite() -
Возвращает
True, если аргумент является конечным числом, иFalse, если аргумент является бесконечностью или NaN.Новое в версии 2.6.
-
is_infinite() -
Возвращает
True, если аргумент является положительной или отрицательной бесконечностью, иFalseв противном случае.Новое в версии 2.6.
-
is_nan() -
Возвращает
True, если аргумент является (тихим или сигнализирующим) NaN, иFalseв противном случае.Новое в версии 2.6.
-
is_normal() -
Возвращает
True, если аргумент является нормальным конечным ненулевым числом с изменённым порядком, большим или равным Emin. ВозвращаетFalse, если аргумент равен нулю, поднормальному, бесконечному или NaN. Примечание: термин нормальный здесь используется в другом смысле, отличном от методаnormalize(), который используется для создания канонических значений.Новое в версии 2.6.
-
is_qnan() -
Возвращает
True, если аргумент является тихим NaN, иFalseв противном случае.Новое в версии 2.6.
-
is_signed() -
Возвращает
True, если аргумент имеет отрицательный знак, иFalseв противном случае. Обратите внимание, что нули и NaN могут иметь знаки.Новое в версии 2.6.
-
is_snan() -
Возвращает
True, если аргумент является сигнализирующим NaN, иFalseв противном случае.Новое в версии 2.6.
-
is_subnormal() -
Возвращает
True, если аргумент является поднормальным, иFalseв противном случае. Число является поднормальным, если оно ненулевое, конечное и имеет изменённый порядок меньше Emin.Новое в версии 2.6.
-
is_zero() -
Возвращает
True, если аргумент является (положительным или отрицательным) нулём, иFalseв противном случае.Новое в версии 2.6.
-
ln([context]) -
Возвращает натуральный логарифм (по основанию e) операнда. Результат правильно округляется с использованием
ROUND_HALF_EVENрежима округления.Новое в версии 2.6.
-
log10([context]) -
Возвращает десятичный логарифм операнда. Результат правильно округляется с использованием
ROUND_HALF_EVENрежима округления.Новое в версии 2.6.
-
logb([context]) -
Для ненулевого числа возвращает изменённый порядок операнда как экземпляр
Decimal. Если операнд равен нулю, возвращаетсяDecimal('-Infinity'), и поднимается флагDivisionByZero. Если операнд равен бесконечности, возвращаетсяDecimal('Infinity').Новое в версии 2.6.
-
logical_and(other[, context]) -
logical_and()- это логическая операция, которая принимает два логических операнда (см. Логические операнды). Результатом является поразряднаяandдвух операндов.Новое в версии 2.6.
-
logical_invert([context]) -
logical_invert()- это логическая операция. Результатом является поразрядное отрицание операнда.Новое в версии 2.6.
-
logical_or(other[, context]) -
logical_or()- это логическая операция, которая принимает два логических операнда (см. Логические операнды). Результатом является поразрядноеorдвух операндов.Новое в версии 2.6.
-
-
logical_xor(other[, context]) -
logical_xor()— это логическая операция, которая принимает два логических операнда (см. Логические операнды). Результатом является побитовое исключающее ИЛИ двух операндов.Новая в версии 2.6.
-
max(other[, context]) -
Подобно
max(self, other), за исключением того, что правило округления контекста применяется перед возвращением, и значенияNaNсигнализируются или игнорируются (в зависимости от контекста и являются ли они сигнализируемыми или бесшумными).
-
max_mag(other[, context]) -
Аналогично методу
max(), но сравнение выполняется с использованием абсолютных значений операндов.Новая в версии 2.6.
-
min(other[, context]) -
Подобно
min(self, other), за исключением того, что правило округления контекста применяется перед возвращением, и значенияNaNсигнализируются или игнорируются (в зависимости от контекста и являются ли они сигнализируемыми или бесшумными).
-
min_mag(other[, context]) -
Аналогично методу
min(), но сравнение выполняется с использованием абсолютных значений операндов.Новая в версии 2.6.
-
next_minus([context]) -
Возвращает наибольшее число, представимое в данном контексте (или в контексте текущей нити, если контекст не задан), которое меньше заданного операнда.
Новая в версии 2.6.
-
next_plus([context]) -
Возвращает наименьшее число, представимое в данном контексте (или в контексте текущей нити, если контекст не задан), которое больше заданного операнда.
Новая в версии 2.6.
-
next_toward(other[, context]) -
Если два операнда не равны, возвращает число, наиболее близкое к первому операнду в направлении второго операнда. Если оба операнда численно равны, возвращает копию первого операнда со знаком, установленным таким же, как знак второго операнда.
Новая в версии 2.6.
-
normalize([context]) -
Нормализует число, удаляя справа все нули и преобразуя любой результат, равный
Decimal('0'), вDecimal('0e0'). Используется для получения канонических значений для атрибутов класса эквивалентности. Например,Decimal('32.100')иDecimal('0.321000e+2')обе нормализуются до эквивалентного значенияDecimal('32.1').
-
number_class([context]) -
Возвращает строку, описывающую класс операнда. Возвращаемое значение является одной из следующих десяти строк.
-
"-Infinity", указывая, что операнд равен отрицательной бесконечности. -
"-Normal", указывая, что операнд — отрицательное нормальное число. -
"-Subnormal", указывая, что операнд отрицательный и субнормальный. -
"-Zero", указывая, что операнд — отрицательный ноль. -
"+Zero", указывая, что операнд — положительный ноль. -
"+Subnormal", указывая, что операнд положителен и субнормален. -
"+Normal", указывая, что операнд — положительное нормальное число. -
"+Infinity", указывая, что операнд равен положительной бесконечности. -
"NaN", указывая, что операнд — тихий NaN (Не число). -
"sNaN", указывая, что операнд — сигнализирующий NaN.
Новая в версии 2.6.
-
-
quantize(exp[, rounding[, context[, watchexp]]]) -
Возвращает значение, равное первому операнду после округления и имеющее порядок второго операнда.
>>> Decimal('1.41421356').quantize(Decimal('1.000')) Decimal('1.414')В отличие от других операций, если длина коэффициента после операции quantize будет больше precision, то сигнализируется
InvalidOperation. Это гарантирует, что, за исключением случаев ошибки, экспонента quantized всегда равна экспоненте правого операнда.Также в отличие от других операций, quantize никогда не сигнализирует Underflow, даже если результат субнормален и неточен.
Если экспонента второго операнда больше, чем у первого, то может потребоваться округление. В этом случае режим округления определяется аргументом
rounding, если он задан, иначе — аргументомcontext; если ни один из аргументов не задан, используется режим округления текущего контекста нити.Если watchexp установлен (по умолчанию), то ошибка возвращается всякий раз, когда результирующая экспонента больше
Emaxили меньшеEtiny.
-
radix() -
Возвращает
Decimal(10), основание (базу), в котором классDecimalвыполняет все свои арифметические операции. Включено для совместимости со спецификацией.Новая в версии 2.6.
-
remainder_near(other[, context]) -
Возвращает остаток от деления 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]) -
Возвращает результат поворота цифр первого операнда на количество позиций, указанное вторым операндом. Второй операнд должен быть целым числом в диапазоне от -precision до precision. Абсолютное значение второго операнда определяет количество позиций поворота. Если второй операнд положительный, поворот происходит влево; в противном случае — вправо. Коэффициент первого операнда дополняется слева нулями до длины precision, если необходимо. Знак и экспонента первого операнда остаются без изменений.
Новая в версии 2.6.
-
same_quantum(other[, context]) -
Проверяет, имеют ли self и other одинаковую экспоненту или оба являются
NaN.
-
scaleb(other[, context]) -
Возвращает первый операнд со скорректированной экспонентой на значение второго. Эквивалентно возвращает первый операнд, умноженный на
10**other. Второй операнд должен быть целым числом.Новая в версии 2.6.
-
shift(other[, context]) -
Возвращает результат сдвига цифр первого операнда на количество позиций, указанное вторым операндом. Второй операнд должен быть целым числом в диапазоне от -precision до precision. Абсолютное значение второго операнда определяет количество позиций сдвига. Если второй операнд положительный, сдвиг происходит влево; в противном случае — вправо. Сдвигаемые в коэффициент цифры — нули. Знак и экспонента первого операнда остаются без изменений.
Новая в версии 2.6.
-
sqrt([context]) -
Возвращает квадратный корень аргумента с полной точностью.
-
to_eng_string([context]) -
Преобразует в строку, используя инженерную нотацию, если требуется экспонента.
Инженерная нотация имеет экспоненту, кратную 3. Это может оставить до 3 цифр слева от десятичной точки и может потребовать добавления одной или двух концевых нулей.
Например, это преобразует
Decimal('123E+1')вDecimal('1.23E+3').
-
to_integral([rounding[, context]]) -
Идентично методу
to_integral_value(). Имяto_integralсохранено для совместимости со старыми версиями.
-
to_integral_exact([rounding[, context]]) -
Округляет до ближайшего целого числа, сигнализируя
InexactилиRoundedпри необходимости, если округление произошло. Режим округления определяется параметромrounding, если он задан, иначе — параметромcontext. Если ни один параметр не задан, используется режим округления текущего контекста.Новая в версии 2.6.
-
-
to_integral_value([rounding[, context]]) -
Округлить до ближайшего целого без сигнализации
InexactилиRounded. Если указано, применяется округление; в противном случае используется метод округления, указанный в предоставленном контексте или в текущем контексте.Изменено в версии 2.6: переименовано из
to_integralвto_integral_value. Старое имя сохранено для совместимости.
-
2.1. Логические операнды
Методы logical_and(), logical_invert(), logical_or(), и logical_xor() ожидают в качестве аргументов логические операнды. Логический операнд — это экземпляр Decimal, у которого показатель степени и знак оба равны нулю, а цифры — все либо 0, либо 1.
3. Контексты
Контексты — это среды для арифметических операций. Они управляют точностью, устанавливают правила округления, определяют, какие сигналы обрабатываются как исключения и ограничивают диапазон показателей степени.
Каждый поток имеет свой текущий контекст, к которому можно получить доступ или изменить его с помощью функций getcontext() и setcontext():
-
decimal.getcontext() -
Возвращает текущий контекст для активного потока.
-
decimal.setcontext(c) -
Устанавливает текущий контекст для активного потока на c.
Начиная с Python 2.5, вы также можете использовать оператор with и функцию localcontext() для временного изменения активного контекста.
-
decimal.localcontext([c]) -
Возвращает менеджер контекста, который установит текущий контекст для активного потока в копию c при входе в оператор with и восстановит предыдущий контекст при выходе из оператора with. Если контекст не указан, используется копия текущего контекста.
Введено в версии 2.5.
Например, следующий код устанавливает текущую точность десятичных чисел в 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 with localcontext(BasicContext): # temporarily use the BasicContext print Decimal(1) / Decimal(7) print Decimal(355) / Decimal(113)
Новые контексты также можно создать с помощью конструктора Context, описанного ниже. Кроме того, модуль предоставляет три предварительно созданных контекста:
-
class decimal.BasicContext -
Это стандартный контекст, определенный в Спецификации общей арифметики десятичных чисел. Точность установлена в девять знаков. Округление установлено в
ROUND_HALF_UP. Все флаги очищены. Все ловушки включены (обрабатываются как исключения), кромеInexact,RoundedиSubnormal.Поскольку многие ловушки включены, этот контекст полезен для отладки.
-
class decimal.ExtendedContext -
Это стандартный контекст, определенный в Спецификации общей арифметики десятичных чисел. Точность установлена в девять знаков. Округление установлено в
ROUND_HALF_EVEN. Все флаги очищены. Ловушки не включены (так что исключения не генерируются во время вычислений).Поскольку ловушки отключены, этот контекст полезен для приложений, которые предпочитают иметь значение результата
NaNилиInfinityвместо генерирования исключений. Это позволяет приложению завершить выполнение в присутствии условий, которые в противном случае остановили бы программу.
-
class decimal.DefaultContext -
Этот контекст используется конструктором
Contextв качестве прототипа для новых контекстов. Изменение поля (например, точности) приводит к изменению значения по умолчанию для новых контекстов, созданных конструкторомContext.Этот контекст наиболее полезен в многопоточных средах. Изменение одного из полей перед запуском потоков приводит к установке системных значений по умолчанию. Изменение полей после запуска потоков не рекомендуется, так как потребуется синхронизация потоков для предотвращения гонок.
В однопоточных средах лучше вообще не использовать этот контекст. Вместо этого просто создавайте контексты явно, как описано ниже.
Значения по умолчанию: точность=28, округление=ROUND_HALF_EVEN, включенные ловушки для Overflow, InvalidOperation и DivisionByZero.
Помимо трех предоставленных контекстов, новые контексты можно создать с помощью конструктора Context.
-
class decimal.Context(prec=None, rounding=None, traps=None, flags=None, Emin=None, Emax=None, capitals=1) -
Создаёт новый контекст. Если поле не указано или равно
None, значения по умолчанию копируются изDefaultContext. Если поле flags не указано или равноNone, все флаги сбрасываются.Поле prec — положительное целое число, устанавливающее точность для арифметических операций в контексте.
Параметр rounding может принимать одно из следующих значений:
-
ROUND_CEILING(в сторонуInfinity), -
ROUND_DOWN(в сторону нуля), -
ROUND_FLOOR(в сторону-Infinity), -
ROUND_HALF_DOWN(к ближайшему, при равенстве — к нулю), -
ROUND_HALF_EVEN(к ближайшему, при равенстве — к ближайшему чётному целому), -
ROUND_HALF_UP(к ближайшему, при равенстве — от нуля), или -
ROUND_UP(от нуля). -
ROUND_05UP(от нуля, если последняя цифра после округления к нулю была бы 0 или 5; в противном случае — к нулю)
Поля traps и flags перечисляют сигналы, которые необходимо установить. В общем случае, новые контексты должны устанавливать только ловушки и оставлять флаги сброшенными.
Поля Emin и Emax — целые числа, задающие допустимые пределы экспонент.
Поле capitals может принимать значения
0или1(значение по умолчанию). Если установлено1, экспоненты выводятся с заглавнойE; в противном случае используется строчнаяe:Decimal('6.02e+23').Изменено в версии 2.6: Добавлен режим округления
ROUND_05UP.Класс
Contextопределяет несколько методов общего назначения, а также большое количество методов для выполнения арифметических операций непосредственно в заданном контексте. Кроме того, для каждого из методов классаDecimal(за исключением методовadjusted()иas_tuple()), описанных выше, существует соответствующий метод классаContext. Например, для экземпляраContextCи экземпляраDecimalx,C.exp(x)эквивалентноx.exp(context=C). Каждый метод классаContextпринимает целое число Python (экземплярintилиlong) в любом месте, где ожидается экземпляр Decimal.-
clear_flags() -
Сбрасывает все флаги в
0.
-
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): ... Inexact: NoneДобавлена в версии 2.7.
-
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) -
Возвращает показатель степени значащей цифры операнда (MSD).
-
-
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]) -
Возвращает
xв степениy, уменьшенное по модулюmodulo, если задано.С двумя аргументами, вычислить
x**y. Еслиxотрицательно, тоyдолжно быть целым. Результат будет неточным, если толькоyцелое и результат конечен и может быть выражен точно в ‘precision’ цифрах. Результат всегда должен быть правильно округлен, используя режим округления контекста текущей нити.С тремя аргументами, вычислить
(x**y) % modulo. Для формы с тремя аргументами следующие ограничения на аргументы:- все три аргумента должны быть целыми
-
yдолжно быть неотрицательным - по крайней мере один из
xилиyдолжен быть ненулевым -
moduloдолжно быть ненулевым и иметь не более ‘precision’ цифр
Значение, полученное от
Context.power(x, y, modulo), равно значению, которое было бы получено, вычислив(x**y) % moduloс неограниченной точностью, но вычисляется более эффективно. Показатель степени результата равен нулю, независимо от показателей степенейx,yиmodulo. Результат всегда точный.Изменено в версии 2.6:
yтеперь может быть нецелым вx**y. Более строгие требования к версии с тремя аргументами.
-
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) -
Преобразует число в строку, используя научную запись.
-
4. Сигналы
Сигналы представляют собой условия, возникающие во время вычисления. Каждый соответствует одному флагу контекста и одному разрешению перехвата контекста.
Флаг контекста устанавливается всякий раз, когда встречается условие. После вычисления флаги можно проверить для получения информации (например, чтобы определить, было ли вычисление точным). После проверки флагов убедитесь, что все флаги очищены перед началом следующего вычисления.
Если разрешение перехвата сигнала в контексте установлено, то условие вызывает исключение 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 x._rescale( non-integer ) 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также сигнализируются.
В следующей таблице обобщена иерархия сигналов:
exceptions.ArithmeticError(exceptions.StandardError)
DecimalException
Clamped
DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
Inexact
Overflow(Inexact, Rounded)
Underflow(Inexact, Rounded, Subnormal)
InvalidOperation
Rounded
Subnormal
5. Примечания по плавающей точке
5.1. Снижение ошибки округления при увеличении точности
Использование десятичной плавающей точки устраняет ошибку десятичного представления (позволяя точно представлять 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')
5.2. Специальные значения
Система чисел для модуля 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-1000000026')
6. Работа с потоками
Функция 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() . . .
7. Рецепты
Ниже приведены несколько рецептов, которые служат вспомогательными функциями и демонстрируют способы работы с классом 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 = map(str, digits)
build, next = result.append, digits.pop
if sign:
build(trailneg)
for i in range(places):
build(next() if digits else '0')
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.
>>> 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.
>>> 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
8. Часто задаваемые вопросы по 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):
'''Remove exponent and trailing zeros.
>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')
'''
return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
В. Есть ли способ преобразовать обычное число с плавающей точкой в 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')
© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/2.7/library/decimal.html