Модуль decimal обеспечивает поддержку быстрой арифметики с правильно округленным десятичным числом с плавающей запятой. Он предлагает несколько преимуществ по сравнению с типом данных float:
- Модуль decimal «основан на модели с плавающей запятой, которая была разработана с учётом потребностей людей c обязательным первостепенным руководящим принципом — компьютеры должны обеспечивать арифметику, которая работает так же, как арифметика, которую люди изучают в школе», — выдержка из спецификации десятичной арифметики.
- Десятичные числа могут быть представлены точно. Напротив, у таких чисел, как 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.
Сигналы — это группы исключительных состояний, возникающих в процессе вычислений. В зависимости от потребностей приложения сигналы могут игнорироваться, рассматриваться как информационные или рассматриваться как исключения. Сигналы в десятичном модуле: Clamped, InvalidOperation, DivisionByZero, Inexact, Rounded, Subnormal, Overflow, Underflow и FloatOperation.
Для каждого сигнала есть флаг и активатор прерывания. Когда сигнал обнаружен, его флаг устанавливается в единицу, затем, если активатор прерывания установлен в единицу, возникает исключение. Флаги залипают, поэтому пользователю необходимо сбросить их перед отслеживанием вычислений.