Números e o objeto Math
Esta aula aborda o sistema de números em JavaScript, incluindo ponto flutuante, o objeto Number, o objeto Math e a introdução ao BigInt. O foco é entender as peculiaridades e armadilhas dos números em JS e como manipulá-los corretamente.
Em JavaScript, todos os números são representados internamente como ponto flutuante de 64 bits (formato IEEE 754), o que inclui tanto inteiros quanto decimais. Isso traz flexibilidade, mas também algumas armadilhas que podem causar resultados inesperados. Nesta aula, vamos explorar como os números funcionam, os métodos disponíveis no objeto Number, as funções matemáticas do objeto Math e a introdução ao BigInt para números inteiros de precisão arbitrária.
Entender essas nuances é fundamental para evitar bugs comuns, como problemas de precisão em cálculos financeiros ou comparações. Vamos começar.
Ponto flutuante e armadilhas
JavaScript usa o padrão IEEE 754 para representar números. Isso significa que números decimais são armazenados em binário, e alguns decimais simples (como 0.1) não podem ser representados exatamente. Por exemplo:
console.log(0.1 + 0.2); // 0.30000000000000004Isso ocorre porque 0.1 e 0.2 em binário são dízimas periódicas. Portanto, operações com decimais podem resultar em pequenos erros de arredondamento. Para evitar problemas, é comum trabalhar com centavos (inteiros) em operações financeiras ou usar funções como toFixed para exibição.
Outra armadilha é a comparação direta de números de ponto flutuante. Nunca use === para comparar decimais após operações. Em vez disso, use uma margem de tolerância (epsilon):
const EPSILON = 1e-10;
console.log(Math.abs(0.1 + 0.2 - 0.3) < EPSILON); // trueAlém disso, valores especiais como NaN (Not-a-Number) e Infinity podem surgir. NaN não é igual a si mesmo, então para verificar use Number.isNaN().
Number e métodos
O objeto Number fornece constantes e métodos úteis. Constantes incluem Number.MAX_VALUE, Number.MIN_VALUE, Number.POSITIVE_INFINITY, Number.NaN, e Number.EPSILON (a menor diferença entre dois números representáveis).
Métodos estáticos importantes:
Number.isInteger(val): retornatruesevalé um inteiro.Number.isFinite(val): verifica sevalé finito (não Infinity nem NaN).Number.isNaN(val): verifica sevalé NaN (mais confiável que globalisNaN).Number.parseInt(str, base)eNumber.parseFloat(str): convertem strings para números.
Métodos de instância (em números primitivos):
toFixed(digits): retorna string com número fixo de casas decimais.toPrecision(digits): retorna string com precisão especificada.toString(base): retorna string na base (2 a 36).
Exemplo:
const num = 123.456;
console.log(num.toFixed(2)); // "123.46"
console.log(num.toString(16)); // "7b.74bc6a7ef9db"
console.log(Number.isInteger(num)); // falseObjeto Math
O objeto Math contém constantes e funções matemáticas. Constantes: Math.PI, Math.E, Math.SQRT2, etc. Funções:
Math.abs(x): valor absoluto.Math.ceil(x),Math.floor(x),Math.round(x): arredondamento.Math.trunc(x): parte inteira (remove decimais).Math.pow(base, exp),Math.sqrt(x),Math.cbrt(x).Math.min(a, b, ...),Math.max(a, b, ...).Math.random(): número pseudoaleatório entre 0 (inclusivo) e 1 (exclusivo).Math.sin(x),Math.cos(x),Math.tan(x)(ângulos em radianos).Math.log(x),Math.log2(x),Math.log10(x).
Exemplo de geração de número aleatório em um intervalo:
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(randomInt(1, 10)); // número entre 1 e 10BigInt (introdução)
BigInt é um tipo de dado que permite representar inteiros de qualquer tamanho, sem limitação de 64 bits. É criado adicionando n ao final de um número ou usando o construtor BigInt():
const big = 123456789012345678901234567890n;
const another = BigInt("123456789012345678901234567890");
console.log(big + 1n); // 123456789012345678901234567891nBigInt não pode ser misturado com Number em operações aritméticas (lança TypeError). Deve-se converter explicitamente (com perda de precisão possível). Exemplo:
const n = 10n;
// console.log(n + 5); // TypeError
console.log(n + BigInt(5)); // 15nComparações entre BigInt e Number são permitidas, mas com cuidado:
console.log(10n == 10); // true (igualdade abstrata)
console.log(10n === 10); // false (estrita)BigInt é útil para criptografia, cálculos com grandes números ou quando a precisão de 64 bits é insuficiente.
Boas práticas
- Para cálculos financeiros, trabalhe com centavos (inteiros) ou use bibliotecas como
decimal.js. - Evite comparar decimais diretamente; use tolerância ou converta para inteiros.
- Use
Number.isNaNem vez deisNaNglobal. - Prefira
Math.truncpara extrair parte inteira (ao contrário deparseIntque pode interpretar strings). - Para números muito grandes, considere BigInt.
Referências
- MDN: Number
- MDN: Math
- MDN: BigInt
- MDN: Operadores aritméticos
- Wikipedia: IEEE 754
- The Floating-Point Guide
Exercícios
Explique por que
0.1 + 0.2 !== 0.3em JavaScript. Como você verificaria se a soma é aproximadamente igual a 0.3?✓ Resposta: Isso ocorre porque 0.1 e 0.2 não podem ser representados exatamente em binário (IEEE 754), resultando em um pequeno erro de arredondamento. Para verificar se a soma é aproximadamente 0.3, podemos usar uma margem de tolerância:Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON.Escreva uma função que receba um número e retorne uma string com duas casas decimais, mas sem arredondamento (truncando). Exemplo:
truncTwo(123.456)deve retornar"123.45".✓ Resposta:function truncTwo(num) { return Math.trunc(num * 100) / 100 + ''; } console.log(truncTwo(123.456)); // "123.45"Use o objeto Math para gerar um número aleatório entre 5 e 15 (inclusive ambos). Escreva o código.
✓ Resposta:const random = Math.floor(Math.random() * (15 - 5 + 1)) + 5; console.log(random); // inteiro entre 5 e 15Qual a diferença entre
Number.isNaN()e a função globalisNaN()? Dê um exemplo onde elas diferem.✓ Resposta:isNaN()converte o argumento para número antes de verificar, enquantoNumber.isNaN()não. Exemplo:isNaN("abc")retornatrue(porque "abc" é convertido para NaN), masNumber.isNaN("abc")retornafalse(pois a string não é NaN).Crie um BigInt a partir do número 2^53 (9007199254740992) e some 1 a ele. Mostre o resultado e explique por que isso é problemático com Number.
✓ Resposta:
Com Number, 9007199254740992 + 1 resulta em 9007199254740992 (pois é o limite de precisão inteira). BigInt permite representar exatamente números maiores.const big = 9007199254740992n; console.log(big + 1n); // 9007199254740993n