4.1 Arredondamento de números de ponto flutuante
Números de ponto flutuante são chamados de
float
ing point number — números
com ponto flutuante: nos EUA, para separar a parte inteira e decimal do número
é usado o ponto. Daí vem o nome float
.
Como já discutimos, ao converter um número de ponto flutuante (float) para um inteiro (int), ele sempre é arredondado para baixo — sua parte decimal é simplesmente descartada. Mas é fácil imaginar uma situação em que você precisa arredondar o número decimal para o inteiro mais próximo. O que fazer nessa situação?
Para isso, no Python existe a função embutida
round()
. Ela foi criada antes da biblioteca math,
por isso não faz parte dela. As funções para arredondar para baixo e para cima
estão na biblioteca math.
A função round()
arredonda o número para o inteiro mais próximo:
round(número_flutuante)
Esta função retornará o inteiro mais próximo ao número de ponto flutuante que foi passado para ela. É importante notar que, se a parte decimal do número for igual a
0.5, a função round()
usa o método de arredondamento para o inteiro par mais próximo. Isso é chamado de "arredondamento bancário" e permite
reduzir o erro sistemático no arredondamento múltiplo. Por exemplo:
Exemplos:
Comando | Resultado |
---|---|
x = round(4.1) | 4 |
x = round(4.5) | 4 |
x = round(4.9) | 5 |
x = round(5.5) | 6 |
A função math.ceil()
arredonda
o número para cima, exemplos:
Comando | Resultado |
---|---|
x = math.ceil(4.1) | 5 |
x = math.ceil(4.5) | 5 |
x = math.ceil(4.9) | 5 |
A função math.floor()
arredonda
o número para baixo, exemplos:
Comando | Resultado |
---|---|
x = math.floor(4.1) | 4 |
x = math.floor(4.5) | 4 |
x = math.floor(4.9) | 4 |
Embora para arredondar o número para baixo seja mais fácil usar a função de conversão de tipo int()
:
Comando | Resultado |
---|---|
x = int(4.9) | 4 |
Se você achar difícil lembrar esses comandos, uma pequena lição de inglês pode ajudar:
math
— matemáticaround
— redondo/arredondarceiling
— tetofloor
— chão
4.2 Como funcionam os números de ponto flutuante
O tipo float
no Python pode armazenar valores no intervalo de
-1.7*10308 a +1.7*10308. Esse intervalo gigantesco de valores é explicado
pelo fato de que o tipo float
é construído de maneira muito diferente em comparação com os tipos inteiros. Cada variável do tipo float contém dois números: o primeiro é chamado de
mantissa, e o segundo — expoente.
Suponha que temos o número 123456789, e o salvamos em
uma variável do tipo float
. Então o número será convertido para a forma
1.23456789*108, e dentro do tipo float
serão armazenados dois números —
23456789 e 8.
Em vermelho está marcada a "parte significativa do número" (mantissa), em verde — o expoente.
Essa abordagem permite armazenar tanto números muito grandes quanto números muito pequenos. Mas já que o tamanho do número é limitado a 8 bytes (64 bits) e parte dos bits é usada para armazenar o expoente (assim como o sinal do número e o sinal do expoente), o comprimento máximo da mantissa é limitado a 15 dígitos.
Esta é uma descrição muito simplificada de como os números de ponto flutuante funcionam, uma versão mais completa pode ser encontrada pesquisando na internet.
4.3 Perda de precisão ao trabalhar com números de ponto flutuante
Ao trabalhar com números de ponto flutuante, é sempre importante ter em mente que
eles são imprecisos. Sempre haverá
erros de arredondamento, erros de conversão
de
sistema decimal para binário e, finalmente, o mais comum —
perda de precisão
ao somar/subtrair números
de dimensões muito diferentes.
O último é a situação mais inesperada para iniciantes em programação.
Se subtrairmos de 109 1/109, teremos novamente 109.
Subtração de números de dimensões muito diferentes | Explicação |
---|---|
|
O segundo número é muito pequeno, e sua parte significativa é ignorada (destacado em cinza). Em laranja estão destacadas 15 dígitos significativos. |
O que dizer, programação não é matemática.
4.4 O perigo de comparar números de ponto flutuante
Outro perigo que os programadores enfrentam é ao comparar números de ponto flutuante. Como durante o trabalho com esses números pode haver acúmulo de erros de arredondamento, há situações em que os números de ponto flutuante deveriam ser iguais, mas não são. E ao contrário: números deveriam ser diferentes, mas são iguais.
Exemplo:
Comando | Explicação |
---|---|
a = 1000000000.0 b = 0.000000001 c = a – b |
Na variável a estará o valor 1000000000.0 Na variável c estará o valor 1000000000.0 (o número na variável b é muito pequeno) |
No exemplo acima, a e c não deveriam ser iguais, mas são.
Ou peguemos outro exemplo:
Comando | Explicação |
---|---|
a = 1.00000000000000001 b = 1.00000000000000002 |
Na variável a estará o valor 1.0 Na variável b estará o valor 1.0 |
Na prática, números de ponto flutuante são comparados assim:
É escolhido um número muito pequeno. Se a diferença entre os números (em módulo) for menor que esse pequeno número, eles são considerados iguais. Exemplo:
a = 0.00000000012
b = 0.000000000011
if abs(a - b) < 0.00001:
print("iguais")
else:
print("diferentes")
GO TO FULL VERSION