Como realizar cálculos decimais precisos usando Python?
Neste artigo, aprenderemos como realizar cálculos decimais precisos em Python.
Métodos usados
Usando a função Decimal() do Módulo decimal
Usando a função fsum() do módulo matemático
A incapacidade dos números de ponto flutuante de representar com precisão todos os números de base 10 é uma desvantagem bem conhecida. Além disso, mesmo cálculos matemáticos simples apresentam poucos erros. Por exemplo -
Exemplo
O programa a seguir mostra a incapacidade dos números inteiros de ponto flutuante de expressar com precisão todos os números da base 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)
Saída
Ao ser executado, o programa acima irá gerar a seguinte saída -
x + y = 7.300000000000001
False
Esses erros são um "recurso" da CPU subjacente ao sistema e do padrão aritmético IEEE 754 usado por sua unidade de ponto flutuante. Não há nada que você possa fazer para evitar tais erros se escrever seu código usando instâncias float porque o tipo de dados float do Python salva dados usando a representação nativa.
Usar o módulo decimal lhe dará maior precisão ao custo de algum desempenho. Vejamos abaixo.
Método 1: Usando a função Decimal() do Módulo decimal
Exemplo
O programa a seguir mostra o uso da função Decimal() para realizar cálculos decimais precisos -
# 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'))
Saída
Ao ser executado, o programa acima irá gerar a seguinte saída -
x + y = 7.3
True
No código acima, pode parecer um pouco estranho à primeira vista, ou seja, especificar números como strings. No entanto, os objetos decimais funcionam exatamente como você deseja (suportando todas as operações matemáticas comuns, etc.). Eles aparecem como números normais quando você os imprime ou os utiliza em funções de formatação de strings.
A capacidade de controlar vários aspectos dos cálculos, como o número de dígitos e o arredondamento, é uma característica fundamental do decimal.
Exemplo
Para fazer isso, crie um contexto local e modifique suas configurações.
# 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)
Saída
Ao ser executado, o programa acima irá gerar a seguinte saída -
0.8518518518518518518518518519
0.852
Aumentando o valor de precisão para ‘60’ para maior precisão
Exemplo
# 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)
Saída
Ao ser executado, o programa acima irá gerar a seguinte saída -
0.8518518518518518518518518519
0.851851851851851851851851851851851851851851851851851851851852
Método 2: usando a função fsum() do módulo matemático
O módulo decimal implementa a "Especificação Aritmética Decimal Geral" da IBM.
Nem é preciso dizer que há uma boa quantidade de opções de personalização que vão além deste artigo.
Iniciantes em Python podem ficar tentados a utilizar o módulo decimal para contornar os problemas de precisão relatados do tipo de dados float. Também é importante conhecer o domínio do seu aplicativo. É simplesmente mais comum utilizar o tipo de ponto flutuante normal ao trabalhar com problemas de ciência ou engenharia, computação gráfica ou muitas outras coisas de natureza científica.
Por exemplo, relativamente poucos elementos no mundo real são medidos com a precisão de 17 dígitos oferecidos pelos floats. Portanto, mesmo pequenos erros de cálculo não têm impacto. A velocidade dos flutuadores nativos também é visivelmente mais rápida, o que é crucial se você precisar executar muitos cálculos.
Exemplo
No entanto, você não pode evitar totalmente os erros. Numerosos algoritmos foram estudados extensivamente por matemáticos, e alguns são melhores que outros no tratamento de erros. Além disso, as consequências resultantes de práticas como cancelamento subtrativo e adição de números grandes e pequenos requerem alguns cuidados.
inputList = [1.23e+18, 1, -1.23e+18]
# observe how the 1 disappears here if we perform sum() on the list
print(sum(inputList))
Saída
Na execução, o programa acima irá gerar a seguinte saída -
0.0
fsum() encontra a soma entre um determinado intervalo ou um iterável. Precisa da importação da biblioteca matemática. É amplamente utilizado em cálculos matemáticos.
Sintaxe
Abaixo está a sintaxe da função.
maths.fsum( iterable )
O iterável pode ser um intervalo, array ou lista.
Tipo de retorno −
Ele retorna um número de ponto flutuante.
Exemplo
O exemplo a seguir pode ser usado para abordar uma implementação mais precisa em 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))
Saída
Ao ser executado, o programa acima irá gerar a seguinte saída -
1.0
Por outro lado, você realmente precisa pesquisar e compreender as propriedades de propagação de erros de outros algoritmos.
Apesar de tudo isso, programas que tratam de assuntos como finanças são onde o módulo decimal é mais utilizado. É incrivelmente desagradável quando pequenas imprecisões aparecem nos cálculos desses sistemas.
O módulo decimal oferece, portanto, um meio de evitar isso. Quando o Python faz interface com bancos de dados, objetos decimais são frequentemente encontrados novamente, especialmente ao acessar dados financeiros.
Conclusão
Aprendemos neste artigo como os cálculos normais falham em casos específicos e por que exigimos cálculos decimais corretos. Aprendemos como realizar cálculos decimais precisos com duas funções separadas: decimal() e fsum(). Também aprendemos como usar a função localcontext() para definir a precisão do resultado.