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: 3.696 ]

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

W3C - World Wide Web Consortium

Web sites dinâmicos com Ajax + JSP + MySQL

MathML - Mathematical Markup Language

XSS - Cross Site Scripting

Jakarta JMeter - Testando o desempenho de seus sites

  
Comentários
[1] Comentário enviado por removido 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 maurixnovatrento 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

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts