1.1 Arredondamento de números de ponto flutuante
Números de ponto flutuante (também conhecidos como floating point number) são números que têm uma parte decimal separada por um ponto nos EUA. Daí vem o nome float.
Como já discutimos, ao converter um número de ponto flutuante (float) para inteiro (int), ele sempre é arredondado para baixo para o inteiro mais próximo — sua parte decimal é simplesmente descartada. Mas facilmente podemos imaginar uma situação onde precisamos arredondar o número para o inteiro mais próximo ou até mesmo para cima. O que fazer?
Para esse tipo de situação, o JavaScript tem uma função embutida chamada round()
. Ela foi criada antes da biblioteca Math,
então não faz parte dela. Funções para arredondar para baixo e para cima estão na biblioteca math.
Função Math.round()
A função Math.round()
arredonda o número para o inteiro mais próximo:
Math.round(float_number)
Essa função vai retornar o número inteiro mais próximo do número de ponto flutuante passado para ela.
Exemplos:
Comando | Resultado |
---|---|
let x = Math.round(4.1); |
4 |
let x = Math.round(4.5); |
5 |
let x = Math.round(4.9); |
5 |
Função Math.ceil()
A função Math.ceil()
arredonda o número para o inteiro para cima:
Comando | Resultado |
---|---|
let x = Math.ceil(4.1); |
5 |
let x = Math.ceil(4.5); |
5 |
let x = Math.ceil(4.9); |
5 |
Função Math.floor()
A função Math.floor()
arredonda o número para o inteiro para baixo:
Comando | Resultado |
---|---|
let x = Math.floor(4.1); |
4 |
let x = Math.floor(4.5); |
4 |
let x = Math.floor(4.9); |
4 |
Se você tem dificuldade em lembrar desses comandos, um breve curso de inglês pode te ajudar:
- math — matemática
- round — círculo/arredondar
- ceiling — teto
- floor — chão
1.2 Estrutura dos números de ponto flutuante
O tipo number em JavaScript pode armazenar valores no intervalo de -1.7*10308 a +1.7*10308. Esse intervalo gigante é possível porque o tipo number é estruturado de forma diferente dos tipos inteiros. Cada variável do tipo number contém dois números: o primeiro é chamado mantissa e o segundo — expoente.
Suponha que temos o número 123456789, e o armazenamos em uma variável do tipo number. Então o número será convertido para a forma 1.23456789*108, e dentro do tipo number serão armazenados os números — 1.23456789 e 8. A parte "significativa" do número (a mantissa) está destacada em vermelho, e o expoente em azul.
Esse método permite armazenar números tanto muito grandes quanto muito pequenos. Mas como o tamanho do número é limitado a 8 bytes (64 bits) e parte dos bits é usada para armazenar expoente (assim como o sinal do número e o sinal do expoente), o máximo de dígitos significativos na mantissa é limitado a 15 dígitos.
Isso é uma descrição simplificada de como os números de ponto flutuante funcionam: uma explicação mais completa pode ser encontrada no link.
1.3 Perda de precisão ao trabalhar com números de ponto flutuante
Ao trabalhar com números de ponto flutuante, sempre devemos ter em mente que esses números são imprecisos. Sempre haverá erros de arredondamento, erros de conversão do sistema decimal para o binário e, por fim, o mais comum — perda de precisão ao somar/subtrair números de ordens de grandeza muito diferentes.
Este último é a situação mais surpreendente para iniciantes em programação.
Se subtrairmos de 109 o número 1/109, obteremos novamente 109.
Subtração de números de tamanhos muito diferentes | Explicação |
---|---|
1000000000.000000000 - 0.000000001 1000000000.000000000 |
O segundo número é tão pequeno que sua parte significativa é ignorada (destacada em cinza). As 15 dígitos significativos estão destacados em vermelho. |
O que podemos dizer, programação não é matemática.
1.4 Risco ao comparar números de ponto flutuante
Outro risco surge para os programadores ao comparar números de ponto flutuante. Como erros de arredondamento podem se acumular ao trabalhar com esses números, é possível que os números de ponto flutuante deveriam ser iguais, mas não são. E vice-versa: os números deveriam ser diferentes, mas são iguais.
Exemplo:
Comando | Explicação |
---|---|
let a = 1000000000.0 let b = 0.000000001 let 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 vejamos outro exemplo:
Comando | Explicação |
---|---|
let a = 1.00000000000000001 let 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:
Se a diferença entre os números (em módulo) for menor que um número muito pequeno, eles são considerados iguais.
Exemplo:
let a = 0.00000000012;
let b = 0.000000000011;
// Se a diferença for menor que 0.00001, considere-os iguais
if (Math.abs(a - b) < 0.00001) {
console.log("iguais");
} else {
console.log("diferentes");
}
GO TO FULL VERSION