Subtraindo números longos em javascript
-
20-09-2019 - |
Pergunta
Por que q == 0 está no script a seguir?
<script>
var start = 1234567890123456789;
var end = 1234567890123456799;
var q = end - start;
alert(q);
</script>
Eu acho que o resultado deveria ser 10.Qual é a maneira correta de subtrair esses dois números?
Solução
Porque os números no JavaScript são pontos flutuantes. Eles têm precisão limitada.
Quando o JavaScript vê um número muito longo, ele o arredonda para o número mais próximo que pode representar como um bóia de 64 bits. Em seu script, start
e end
Seja arredondado para o mesmo valor.
alert(1234567890123456789); // says: 1234567890123456800
alert(1234567890123456799); // says: 1234567890123456800
Não há uma maneira interna de fazer aritmética precisa em números inteiros grandes, mas você pode usar uma biblioteca Biginteger, como Este.
Outras dicas
Jason já postou o porquê. Para uma solução, você pode obter uma biblioteca Bigint JavaScript em http://www-cs-students.stanford.edu/~tjw/jsbn/
const subtract = (a, b) => [a, b].map(n => [...n].reverse()).reduce((a, b) => a.reduce((r, d, i) => {
let s = d - (b[i] || 0)
if (s < 0) {
s += 10
a[i + 1]--
}
return '' + s + r
}, '').replace(/^0+/, ''))
Use melhor a biblioteca grande inteira para essas coisas para lidar com todos os diferentes casos de teste.
Isso é apenas para o caso geral que você pode usar ....
Está explicado no Documentação JavaScript:
De acordo com o padrão ECMAScript, existe apenas um tipo de número: o valor IEEE 754 de formato binário de 64 bits de precisão dupla (números entre
-(2
53
-1)
e2
53
-1
). Não existe um tipo específico para números inteiros.
Página da Wikipédia sobre formato de ponto flutuante de precisão dupla explica:
Entre
2
52
= 4,503,599,627,370,496
e2
53
= 9,007,199,254,740,992
os números representáveis são exatamente os inteiros.Para a próxima faixa, de2
53
para2
54
, tudo é multiplicado por2
, então os números representáveis são os pares, etc.
(Todos os números inteiros menores que 2
52
são representados exatamente.)
1234567890123456789
e 1234567890123456799
são maiores que 2
60
= 1152921504606846976
.Nessa magnitude, apenas cerca de 1% dos números inteiros são armazenados exatamente usando o formato de ponto flutuante de precisão dupla.
Esses dois não podem ser armazenados exatamente.Ambos são arredondados para 1234567890123456800
.
O Documentação JavaScript também explica como saber se um número inteiro está armazenado exatamente:
[...] e começando com ECMAScript 6, você também pode verificar se um número está no intervalo de números de ponto flutuante de precisão dupla usando
Number.isSafeInteger()
assim comoNumber.MAX_SAFE_INTEGER
eNumber.MIN_SAFE_INTEGER
.Além desse intervalo, os números inteiros em JavaScript não são mais seguros e serão uma aproximação de ponto flutuante de precisão dupla do valor.