Domine Números Decimais em Python: Guia Completo de Floats e o Módulo Decimal

Em Python, um dos tipos de dados mais frequentemente empregados é o `float`, que se destina a representar números de ponto flutuante. Estes números, sejam eles positivos ou negativos, caracterizam-se pela presença de uma parte decimal. Adicionalmente, os números de ponto flutuante abrangem aqueles expressos em notação científica, utilizando os caracteres ‘e’ ou ‘E’ para designar uma potência de 10.

O tipo de dado `float` assume uma importância crucial, dada a sua capacidade de representar uma vasta gama de números reais, desde valores extremamente pequenos até magnitudes imensas.

A seguir, alguns exemplos de números de ponto flutuante em Python:

# Números float
a = 20.0
b = -51.51345
c = 65e7
d = -1.08E12
e = 2E10

print(type(a))
print(type(b))
print(type(c))
print(type(d))
print(type(e))

Resultado:

<class 'float'>
<class 'float'>
<class 'float'>
<class 'float'>
<class 'float'>

Além disso, eles viabilizam cálculos mais precisos em comparação com tipos de dados como os inteiros, os quais desconsideram a porção fracionária dos números. Por exemplo, um número como 3,142 seria simplificado para 3 ao ser representado como um inteiro.

Em contrapartida, o tipo `float` preserva o valor real, como 3.142. Por conseguinte, os valores flutuantes são mais adequados para cálculos matemáticos, uma vez que geram resultados mais acurados.

Nesse contexto, os valores de ponto flutuante encontram vasto uso em modelagem de fenômenos do mundo real, aprendizado de máquina, ciência de dados, análise financeira e econômica, cálculos matemáticos, geração de gráficos e visualizações, além de cálculos científicos e de engenharia.

Inteiros vs. Float em Python

Os inteiros são outro tipo de dado bastante utilizado em Python. Ao contrário dos números de ponto flutuante, os inteiros não possuem parte decimal. Os inteiros englobam números inteiros positivos, números negativos e o zero, todos eles desprovidos de porções fracionárias.

Os inteiros são úteis quando realizamos operações que envolvem números inteiros, como contagem ou indexação. Em Python, valores inteiros são denotados como `int`.

Alguns exemplos de inteiros são apresentados abaixo:

a = 0
b = 968
c = -14

print(type(a))
print(type(b))
print(type(c))

Resultado:

<class 'int'>
<class 'int'>
<class 'int'>

Algumas das diferenças entre inteiros e números de ponto flutuante em Python incluem:

Característica Inteiros (`int`) Números de ponto flutuante (`float`)
Representação Representam números inteiros, suas contrapartes negativas e zero, todos sem casa decimal. Números reais com ponto decimal
Precisão Precisão ilimitada, portanto, não há limite para o tamanho ou tamanho de um valor int. A única restrição será a memória disponível em seu sistema. Tem precisão limitada. O maior valor flutuante que você pode armazenar é cerca de 1,8 x 10308
Uso de memória Usa menos memória que `float` Usa mais memória do que valores inteiros
Operações bit a bit Amplamente usado em operações bit a bit Quase nunca é usado em operações bit a bit
Uso Normalmente usado em contagem, indexação e operações bit a bit Amplamente usado em medições, cálculos científicos e a maioria das operações matemáticas

Diferentes maneiras de criar e usar floats em Python

Uma forma direta de trabalhar com valores flutuantes em Python é atribuir um valor do tipo `float` a uma variável, como demonstrado abaixo:

# Atribui um valor float a uma variável
a = 3.142

Outra forma de se obter valores do tipo `float` é por meio da conversão de inteiros ou strings numéricas usando o construtor `float()`. Caso se passe uma string ou um inteiro numérico para `float()`, ele será convertido em um valor float, conforme ilustrado:

number1 = 2524
numString1 = "513.523"
numString2 = "1341"
# Converte para um float e armazena o valor float em uma variável
a = float(number1)
print(a)
b = float(numString1);
print(b)
c = float(numString2)
print(c)

Resultado:

2524.0
513.523
1341.0

Neste exemplo, tanto o inteiro quanto as strings são convertidos em valores flutuantes usando `float()` e posteriormente armazenados em variáveis, que são impressas, exibindo o valor flutuante resultante após a conversão.

Uma forma adicional de se obter valores flutuantes é realizando cálculos matemáticos, como a divisão, conforme ilustrado abaixo:

num1 = 20
num2 = 3
result = num1/num2
print("Resultado da divisão como um inteiro:")
print(int(20/3))
print("Resultado da divisão como um valor float:")
print(result)
print(type(result))

Resultado:

Resultado da divisão como um inteiro:
6
Resultado da divisão como um valor float:
6.666666666666667
<class 'float'>

Neste exemplo, note que o valor `float` nos fornece uma resposta mais precisa em comparação com a divisão que resulta em um número inteiro.

Ao lidar com números flutuantes em Python, você pode se deparar com alguns resultados singulares devido à forma como os valores flutuantes são representados internamente no computador. Os números de ponto flutuante são representados no hardware do computador como frações de base 2 (binárias).

Contudo, a maioria das frações decimais, em particular aquelas com decimais recorrentes, não pode ser representada de forma precisa como uma fração binária. Como resultado, os números de ponto flutuante são frequentemente armazenados como uma aproximação do valor real.

Para ilustrar isso na prática, considere o valor flutuante 0,3. Se você atribuir 0,3 a uma variável, internamente, ele não será armazenado exatamente como 0,3. Para observar isso, podemos utilizar a função `format()` a fim de visualizar como o 0,3 é representado internamente. `format()` nos possibilita exibir um número desejado de algarismos significativos de um valor com o qual estamos trabalhando. No exemplo abaixo, estamos imprimindo 0,3 com 20 algarismos significativos para verificar como ele é armazenado internamente.

num = 0.3
print("num com 20 algarismos significativos")
print(format(num, '.20f'))
print("Valor que armazenamos para num")
print(num)

Resultado:

num com 20 algarismos significativos
0.29999999999999998890
Valor que armazenamos para num
0.3

Como se pode observar, o valor 0,3 que atribuímos a uma variável chamada `num` não é armazenado internamente de maneira exata. Ao imprimir a variável `num`, obtém-se um valor arredondado.

Devido a esse fato, podem surgir resultados inesperados ao se trabalhar com valores flutuantes. Por exemplo, se você calcular manualmente 0,3 + 0,3 + 0,3, a resposta será 0,9. No entanto, para o Python, isso não é o caso, pois internamente ele armazena aproximações das frações binárias do valor real. Isso pode ser observado abaixo:

sum = 0.3 + 0.3 + 0.3
answer = 0.9
print("A soma é igual à resposta: ")
print(sum == answer)
print("A representação interna da soma é: ")
print(sum)
print("A resposta do cálculo manual é: ")
print(answer)

Resultado:

A soma é igual à resposta: 
False
A representação interna da soma é: 
0.8999999999999999
A resposta do cálculo manual é: 
0.9

Portanto, ao trabalhar com valores flutuantes, é importante ter em mente que o Python não armazena valores exatos internamente, mas sim aproximações do valor real.

Assim sendo, ao comparar valores flutuantes, convém inicialmente arredondá-los para o mesmo número de algarismos significativos. Para se obter maior precisão ao trabalhar com números de ponto flutuante em Python, considere usar o módulo `decimal` embutido.

Módulo Decimal em Python

Em situações onde a alta precisão é crucial e imprescindível, como em cálculos financeiros e científicos, o uso do `float` não é o mais indicado. Para assegurar a precisão ao lidar com números de ponto flutuante, emprega-se o módulo `decimal`, que é nativo do Python.

Ao contrário do `float`, que é armazenado como representações binárias de ponto flutuante dependentes da máquina, o módulo `decimal` armazena os números de ponto flutuante usando representação baseada em decimal, independente da máquina, o que oferece maior precisão.

Ademais, o módulo `decimal` tem a capacidade de representar os números decimais exatamente como eles são, e utilizá-los de forma precisa nos cálculos. Ele também oferece aritmética de ponto flutuante decimal corretamente arredondada.

Para iniciar o uso do módulo `decimal`, importe-o em seu arquivo Python da seguinte maneira:

import decimal

Para ilustrar o benefício do módulo `decimal`, vamos refazer a comparação anterior entre a soma de 0,3 + 0,3 + 0,3 e o valor 0,9. O código para fazer isso é mostrado abaixo:

import decimal

sum = decimal.Decimal('0.3') + decimal.Decimal('0.3') + decimal.Decimal('0.3')
answer = decimal.Decimal('0.9')
print("A soma é igual à resposta: ")
print(sum == answer)
print("A representação interna da soma é: ")
print(sum)
print("A resposta do cálculo manual é: ")
print(answer)

Resultado:

A soma é igual à resposta: 
True
A representação interna da soma é: 
0.9
A resposta do cálculo manual é: 
0.9

Portanto, ao lidar com números de ponto flutuante e necessitar de alta precisão, lembre-se sempre de utilizar o módulo `decimal`.

Erros comuns ao trabalhar com carros alegóricos

Diversos erros que surgem ao trabalhar com o tipo `float` em Python resultam da compreensão inadequada de como os números de ponto flutuante são representados internamente pelo Python. Por exemplo, um valor como 0,3 não será armazenado exatamente como 0,3. Portanto, é provável que você encontre erros ao trabalhar com valores flutuantes, presumindo que eles sejam armazenados de forma exata.

Um erro comum é o erro de arredondamento, que pode surgir ao realizar cálculos matemáticos em valores flutuantes. Dado que o Python não pode representar os valores flutuantes reais, é possível que você encontre erros de arredondamento em que os resultados podem não ser os esperados.

Devido a erros como os de arredondamento, é provável que você se depare com problemas ao tentar fazer comparações de igualdade entre valores de ponto flutuante. É essencial ter muita cautela ao trabalhar com `float` em Python e estar ciente de resultados inesperados.

A maneira mais eficaz de evitar todos os erros que podem surgir ao trabalhar com valores flutuantes é utilizar o módulo `decimal` embutido. Dessa forma, os resultados dos cálculos com números de ponto flutuante serão mais previsíveis e precisos.

Conclusão

Como programador que trabalha com Python, o tipo de dado `float` é de uso constante. Para evitar erros com este tipo de dados, é essencial entender como o Python representa os números flutuantes internamente. Visto que o Python não consegue armazenar os números flutuantes reais, é aconselhável evitar realizar comparações exatas de igualdade com valores flutuantes, pois isso pode levar a erros.

Caso você necessite de resultados precisos em sua aplicação, evite utilizar valores flutuantes. Em vez disso, empregue o módulo `decimal` embutido, que produz resultados precisos de números de ponto flutuante, representando-os exatamente como são e de maneira independente da máquina.

Você também pode consultar Python Itertools Functions e Python Try Except.