Por que o Javascript é ruim em matemática?

Você provavelmente já escutou alguém falar que "Javascript é ruim com contas", e essa afirmação não está inteiramente errada. Neste artigo nos aprofundaremos um pouco mais nesse tema.

[ Hits: 1.258 ]

Por: Henrique Marques Fernandes em 11/07/2020 | Blog: https://marquesfernandes.com


Por que o Javascript é ruim em matemática?



Você provavelmente já escutou alguém falar que "Javascript é ruim com contas", e essa afirmação não está inteiramente errada. Por ignorância algumas pessoas chegam a comparar com outras linguagens, já cheguei a escutar "Usa Python que ela sabe fazer conta", talvez por ser uma linguagem com alta popularidade no campo de ciência de dados muita gente assume isso. Não defendendo o JS, nem criticando o Python, apenas que vocês entendam que muitas linguagens compartilham desse mesmo problema do Javascript.

Observando o erro na prática

Vamos imaginar o seguinte cenário, eu quero me inscrever na academia e resolvi pagar trimestralmente, eu tenho disponível de dinheiro R$600,90 e o preço da mensalidade da academia é de R$200,30, teoricamente se você realizar essa conta você tem dinheiro suficiente disponível, mas quando tentamos replicar essa lógica para o código, não é o que acontece:

const meuDinheiro = 600.90;
const precoDaMensalidade = 200.30;
const totalDeMensalidades = precoDaMensalidade * 3;

// Resultado: true
console.log(meuDinheiro >= totalDeMensalidades);

// Resultado: 60090
console.log(totalDeMensalidades);

Agora para provar meu ponto, vamos ver o mesmo exemplo em Python:

meuDinheiro = 600.90;
precoDaMensalidade = 200.30;
totalDeMensalidades = precoDaMensalidade * 3;

<strong># Resultado: false</strong><br
print(meuDinheiro >= totalDeMensalidades);

<strong># Resultado: 600.9000000000001</strong><br
print(totalDeMensalidades);

Ora, ora, quem diria não é mesmo?

O problema: Ponto flutuante e Arrendondamento

Para tentar evitar confusão, como o conceito de ponto flutuante não é algo muito fácil de entender, vamos tentar explicar superficialmente o conceito, mas se você deseja ir a fundo e entender na raiz, eu recomendo a leitura desse artigo em inglês.

No JavaScript, todos os números são números de ponto flutuante IEEE 754. Devido à natureza binária de sua codificação, alguns números decimais não podem ser representados com precisão perfeita.

Para entender o que é um ponto flutuante, primeiro você precisa entender de que existem muitos tipos de números e maneiras de representar-los, pelos quais passaremos. Chamamos 1 de número inteiro - é um número inteiro sem valores fracionários.

1/2 é o que é a famosa fração. Isso implica que o número inteiro 1 está sendo dividido em 2. Esse conceito de frações é muito importante na derivação de pontos flutuantes.

0,5 é conhecido como um número decimal. No entanto, uma distinção muito importante precisa ser feita - 0,5 é apenas a representação decimal (base 10) da fração 1/2. É assim que 1/2 é representado quando escrito como um número base 10 - para este artigo, podemos chamar isso de notação de ponto. Chamamos 0,5 de representação finita porque os números na representação da fração são finitos - não há mais números após 5 em 0,5. Uma representação infinita seria, uma dizima periódica, por exemplo, 0,3333... ao representar 1/3.

Existe outra maneira de representar números que não sejam números inteiros, frações ou notações decimais. Você já deve ter visto isso antes, são as notações científicas, algo assim: 6.022 x 102 3 e esse é o formato IEEE 754 adotado. Esse formato tem uma limitação de 64 bits, então quando o limite de armazenamento do número é atingido, você precisará arredondar o último dígito para cima ou para baixo.

Seu primeiro pensamento pode ser tentar arredondar para a segunda casa decimal. Infelizmente, o arredondamento interno do JavaScript funciona apenas para o número inteiro mais próximo.

Como calcular com precisão usando o JavaScript

Agora que você entendeu o problema, embora o erro de precisão seja baixo, ele pode causar sérios problemas de lógica e consistência de dados, mas então como fazer com o que o JavaScript faça as contas corretamente e com precisão?

Existem algumas soluções propostas, algumas mais restritas indicam que a melhor maneira é multiplicar para números inteiros antes de fazer as contas:

const meuDinheiro = 600.90 * 100;
const precoDaMensalidade = 200.30 * 100;
const totalDeMensalidades = precoDaMensalidade * 3;

// Outputs: true
console.log(meuDinheiro >= totalDeMensalidades);

// Outputs: 60090
console.log(totalDeMensalidades);
E outras soluções usam a transformação e calculo baseado em strings, o que pode ser útil mas vem com o custo de performance.

A melhor e mais fácil solução para lidar com contas e pontos flutuantes no JavaScript é utilizando algumas bibliotecas já testadas e aprovadas pela comunidade, como dinerojs ou mathjs.

Mas então, todas as linguagens tem esse problema?

Entenda que outras linguagens, como C #, Java, Python e muitas outras, também usam o IEEE-754, portanto, não pense que você vai se safar desse problema simplesmente mudando a linguagem.

A diferença está em que outras linguagens geralmente têm outros tipos de armazenamento de números que você pode usar e que evitam esses problemas. Por exemplo, o C # tem um tipo nativo de decimal que deve ser usado para tarefas como cálculos monetários.

O que precisamos sempre entender é que cada aplicação tem um foco e cada linguagem tem suas vantagens, se você tem uma aplicação que não vai fazer contas extensivas e que o custo operacional não será impactante, vá com Javascript, mas se esse não for o caso, procure uma linguagem que supra as necessidades de seu projeto. Minha dica é: não tenha amor a linguagem e nem a códigos e sim em solucionar problemas.

Referências


Previamente publicado em: https://marquesfernandes.com/por-que-o-javascript-e-ruim-em-matematica/

   

Páginas do artigo
   1. Por que o Javascript é ruim em matemática?
Outros artigos deste autor

Como desenvolver com Docker no Linux dentro do Windows sem dual boot - WSL 2

Leitura recomendada

Diferenças de sites Web Standards

Listar dados em MySQL utilizando PHP e AJAX (parte 1)

Como minimizar CSS e Javascript via linha de comando

XSS - Cross Site Scripting

Jakarta JMeter - Testando o desempenho de seus sites

  
Comentários
[1] Comentário enviado por ruankl em 11/07/2020 - 10:08h

Muito bom! Eu tive problemas recentemente com o gateway de pagamentos wirecard envolvendo transferência de saldo, e a solução que encontrei foi justamente essa multiplicação por números inteiros!

[2] Comentário enviado por mauricio123 em 11/07/2020 - 13:37h

É uma boa dica. Não programo muito para mim e ainda não tenho trabalho na área. Talvez isso será muito útil para mim no futuro.

___________________________________
Conhecimento não se Leva para o Túmulo.

[3] Comentário enviado por edivandjs em 11/07/2020 - 13:59h

Ótimo. Muito interessante.

________________
“Quem combate monstruosidades deve cuidar para que não se torne um monstro. E se você olhar longamente para um abismo, o abismo também olha para dentro de você”
Nietzsche.


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner
Linux banner
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts