Как выполнить точные десятичные вычисления с помощью Python?
В этой статье мы научимся выполнять точные десятичные вычисления в Python.
Используемые методы
Использование функции Decimal() модуля decimal
Использование функции fsum() математического модуля
Неспособность числ с плавающей запятой точно представлять все числа с основанием 10 — хорошо известный недостаток. Более того, даже простые математические вычисления содержат мало ошибок. Например —
Пример
Следующая программа показывает неспособность целых чисел с плавающей запятой точно выразить все числа по основанию 10:
x = 4.2
y = 3.1
# printing the sum of both the variables
print("x + y =", x + y)
# checking if the sum is both the variables is equal to 7.3
print((x + y) == 7.3)
Выход
При выполнении вышеуказанная программа сгенерирует следующий вывод:
x + y = 7.300000000000001
False
Эти ошибки являются «особенностью» ЦП, лежащего в основе системы, и стандарта арифметики IEEE 754, который используется его модулем вычислений с плавающей запятой. Вы ничего не сможете сделать, чтобы предотвратить такие ошибки, если пишете свой код с использованием экземпляров с плавающей запятой, поскольку тип данных Python с плавающей запятой сохраняет данные, используя собственное представление.
Использование десятичного модуля даст вам большую точность за счет некоторого снижения производительности. Давайте посмотрим на это ниже.
Способ 1: использование функции Decimal() десятичного модуля.
Пример
В следующей программе показано использование функции Decimal() для выполнения точных десятичных вычислений:
# importing Decimal from decimal module
from decimal import Decimal
x = Decimal('4.2')
y = Decimal('3.1')
# printing the sum of both the variables
print("x + y =", x + y)
# checking if the sum is both the variables is equal to 7.3 using by passing the sum to the Decimal Function
print((x + y) == Decimal('7.3'))
Выход
При выполнении вышеуказанная программа сгенерирует следующий вывод:
x + y = 7.3
True
В приведенном выше коде на первый взгляд может показаться немного странным, например, указание чисел в виде строк. Тем не менее, десятичные объекты работают именно так, как вам хотелось бы (поддерживая все распространенные математические операции и т. д.). Они выглядят как обычные числа, когда вы их печатаете или используете в функциях форматирования строк.
Возможность контролировать некоторые аспекты вычислений, такие как количество цифр и округление, является ключевой особенностью decimal.
Пример
Для этого создайте локальный контекст и измените его настройки.
# importing localcontext from decimal module
from decimal import localcontext
x = Decimal('2.3')
y = Decimal('2.7')
# dividing x by y(returns as a floating-point number)
print(x / y)
with localcontext() as context:
# rounding the number upto 3 digits i.e, precision 3
context.prec = 3
# Dividing x by y with precision set to 3
print(x / y)
Выход
При выполнении вышеуказанная программа сгенерирует следующий вывод:
0.8518518518518518518518518519
0.852
Увеличение значения точности до «60» для более высокой точности.
Пример
# importing localcontext from decimal module
import decimal
from decimal import localcontext
x = decimal.Decimal('2.3')
y = decimal.Decimal('2.7')
# dividing x by y(returns as a floating-point number)
print(x / y)
with localcontext() as context:
# Rounding the number upto 60 digits i.e, precision 60
context.prec = 60
# Dividing x by y with precision set to 3
print(x / y)
Выход
При выполнении вышеуказанная программа сгенерирует следующий вывод:
0.8518518518518518518518518519
0.851851851851851851851851851851851851851851851851851851851852
Способ 2. Использование функции fsum() математического модуля.
Десятичный модуль реализует «Общую спецификацию десятичной арифметики» IBM.
Само собой разумеется, что существует множество вариантов настройки, выходящих за рамки этой статьи.
У новичков Python может возникнуть соблазн использовать модуль decimal, чтобы обойти проблемы с точностью данных типа float. Также важно знать область вашего приложения. Просто более типично использовать обычный тип с плавающей запятой при работе с научными или инженерными задачами, компьютерной графикой или большинством других задач научного характера.
Например, относительно немногие элементы в реальном мире измеряются с точностью 17 цифр, обеспечиваемой числами с плавающей запятой. Поэтому даже незначительные ошибки в расчетах не имеют никакого значения. Скорость родных чисел с плавающей запятой также заметно выше, что очень важно, если вам нужно выполнить много вычислений.
Пример
Однако полностью избежать ошибок невозможно. Математики тщательно изучали многочисленные алгоритмы, и некоторые из них лучше других справляются с ошибками. Кроме того, некоторой осторожности требуют последствия, возникающие в результате таких практик, как вычитание и сложение больших и малых чисел.
inputList = [1.23e+18, 1, -1.23e+18]
# observe how the 1 disappears here if we perform sum() on the list
print(sum(inputList))
Выход
При выполнении вышеуказанная программа сгенерирует следующий вывод:
0.0
fsum() находит сумму между заданным диапазоном или итерацией. Требуется импорт математической библиотеки. Его широко используют в математических расчетах.
Синтаксис
Ниже приведен синтаксис функции.
maths.fsum( iterable )
Итерируемый объект может быть диапазоном, массивом или списком.
Тип возвращаемого значения –
Он возвращает число с плавающей запятой.
Пример
Следующий пример можно использовать для более точной реализации в math.fsum() —
# importing math module
import math
# input list
inputList = [1.23e+18, 1, -1.23e+18]
# adding the sum of elements of the list using the fsum() function
print(math.fsum(inputList))
Выход
При выполнении вышеуказанная программа сгенерирует следующий вывод:
1.0
Напротив, вам действительно необходимо изучить и понять свойства распространения ошибок других алгоритмов.
Несмотря на все это, в программах, посвященных таким предметам, как финансы, десятичный модуль используется чаще всего. Невероятно неприятно, когда в расчетах таких систем появляются мелкие неточности.
Таким образом, десятичный модуль предлагает возможность избежать этого. Когда Python взаимодействует с базами данных, объекты Decimal часто встречаются снова, особенно при доступе к финансовым данным.
Заключение
В этой статье мы узнали, как обычные вычисления не работают в определенных случаях и почему нам нужны правильные десятичные вычисления. Мы научились выполнять точные десятичные вычисления с помощью двух отдельных функций: decimal() и fsum(). Мы также узнали, как использовать функцию localcontext() для установки точности результата.