В данном руководстве мы рассмотрим использование модуля для работы с десятичными числами, который включен в стандартную библиотеку Python.
Введение
В Python есть числовые типы данных, такие как int, float и комплексные числа, но из-за машинной зависимости чисел с плавающей точкой нам нужен более точный тип данных для вычислений, требующих высокой точности. В этой статье мы рассмотрим модуль decimal в Python, который реализует десятичные числа с точностью до 28 цифр.
Использование
Python реализует десятичные числа как числа двойной точности с плавающей точкой, которые зависят от машины. Для вычислений, где точность критична для бизнеса, числа с плавающей точкой могут вызывать ошибки при выполнении на другой машине. Поэтому для таких приложений нам нужен независимый от машины тип данных для реализации десятичных чисел, который был реализован с помощью модуля decimal в Python. Кроме того, модуль decimal реализует десятичное число с точностью до 28 десятичных цифр, в то время как числа с плавающей запятой имеют точность до 18 цифр.
Это можно наблюдать в следующем примере
import decimal float_num = 100 / 3 print(float_num) decimal_num = decimal.Decimal(100) / decimal.Decimal(3) print(decimal_num)
Вывод программы
33.333333333333336 33.33333333333333333333333333
Вторая причина использования десятичных чисел вместо чисел с плавающей точкой заключается в том, что в Python числа не могут быть представлены с использованием их точного значения, а используется только приближение, что может быть опасно для критически важных программ.
Из-за аппроксимации значения с плавающей точкой дают разные результаты для разных вычислений. Например, если мы сложим 1,2 и 2,2, используя значения с плавающей точкой, ответ должен быть равен 3,4. Но когда мы сравним добавленное число и 3,4, они не будут равны. Эта ошибка возникает из-за приближений в числах с плавающей запятой, из-за которых сумма 1,2 и 2,2 не равна 3,4.
Поэтому в случаях, когда необходимо сравнить десятичные значения, следует использовать десятичный модуль, а не числа с плавающей точкой.
Это может быть более понятно из следующего примера.
a = 1.2 b = 2.2 c = 3.4 d = a + b print("a:", a) print("b:", b) print("c:", c) print("a+b:", d) print("a+b==c?:", d == c)
Вывод программы
a: 1.2 b: 2.2 c: 3.4 a+b: 3.4000000000000004 a+b==c?: False
Настройка контекста
Чтобы использовать модуль decimal в Python, достаточно его импортировать следующим образом.
import decimal
Импортированный модуль имеет предопределенный контекст, который содержит значения по умолчанию для точности, округления, флагов, минимально и максимально допустимых чисел. Мы можем посмотреть значения контекста с помощью метода getcontext() следующим образом.
import decimal print(decimal.getcontext())
Вывод программы
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])
Мы также можем установить точность и другие параметры контекста. Чтобы изменить точность на 2 цифры вместо 28, мы можем использовать следующую программу.
import decimal decimal.getcontext().prec = 2 print(decimal.getcontext())
Вывод программы
Context(prec=2, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])
По умолчанию, при округлении десятичных чисел с помощью модуля decimal, числа округляются равномерно. Мы можем изменить это поведение, изменив значение «rounding» в контексте следующим образом.
import decimal decimal.getcontext().rounding = "ROUND_HALF_DOWN" print(decimal.getcontext())
Вывод программы
Context(prec=28, rounding=ROUND_HALF_DOWN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])
Все арифметические операции над десятичными числами, определяемые модулем decimal, аналогичны операциям над числами с плавающей запятой. Разница заключается в точности значений из-за различий в реализации.
Округление значений
Мы можем округлять числа до определенных цифр с помощью функции round(). Функция round принимает десятичное число, которое нужно округлить, в качестве первого аргумента и количество цифр, до которых его нужно округлить, в качестве второго аргумента и возвращает округленное десятичное значение следующим образом.
import decimal num1 = decimal.Decimal(100) num2 = decimal.Decimal(3) print("Первое число:", num1) print("Второе число:", num2) num3 = num1 / num2 print("Первое число разделенное на второе число:", num3) num4 = round(num3, 2) print("Округленное число:", num4)
Вывод программы
Первое число: 100 Второе число: 3 Первое число разделенное на второе число: 33.33333333333333333333333333 Округленное число: 33.33
Сравнение десятичных чисел
Как было показано в одном из разделов выше, сравнение чисел с плавающей запятой может привести к неправильным результатам, но десятичные числа являются точными, и их сравнение всегда даст желаемый результат. Это можно увидеть следующим образом.
import decimal a = decimal.Decimal("1.2") b = decimal.Decimal("2.2") c = decimal.Decimal("3.4") d = a + b print("a:", a) print("b:", b) print("c:", c) print("a+b:", d) print("a+b==c?:", c == d)
Вывод программы
a: 1.2 b: 2.2 c: 3.4 a+b: 3.4 a+b==c?: True
В приведенном выше коде видно, что мы преобразовали строки в десятичные числа вместо того, чтобы преобразовывать числа с плавающей точкой в десятичные. Это сделано потому, что если мы преобразуем число с плавающей точкой в десятичное, то ошибка аппроксимации распространится на десятичное число, и мы не получим желаемого результата.
Заключение
В этой статье мы изучили недостатки выполнения арифметических операций с числами с плавающей точкой и использовали модуль decimal для реализации тех же операций без ошибок в Python. Мы также можем написать программы, использованные в этой статье, с обработкой исключений, используя python try except, чтобы сделать программы более надежными и систематически обрабатывать ошибки.
Оставайтесь с нами для получения новых информативных статей.
Здравствуйте очень доходчиво и с примерами, хорошая работа и сайт, у меня есть один вопрос почти в этой теме: как число например 7.123 сделать чтобы было 0.123 для последующих калькуляций. Заранее спасибо).
Егор, привет! Спасибо за сайт, много полезного!
У меня есть вопрос. Очень важный для меня и моих расчетов.
В python в функции для округлений round в случае последнего необходимого разряда числа после запятой = 5 действует так называемое банковское округления, кажется в сторону ближайшего нечетного разряда.
Т.е. если число = 8,3235 надо округлить до 3 знаков после запятой, то round округлит его так 8,323.
Но если требуется классическое математическое округление, которое при 5 — ке всегда округляет в большую сторону, надо танцевать с бубном.
Подскажи пожалуйста наилучшее решение. Предыдущие поиски ничего не дали, к сожалению.
так есть же у модуля decimal режимы округления.
https://docs.python.org/3/library/decimal.html#rounding-modes смотрели здесь? 🙂
Всё доходчиво понятно….с примерами с докозательствами …циры наглядно подтверждают эфективность данной программы !
🙂
Автор Молодец….статья интересная ….продолжай писать подобное )))
спасибо, Андрей