Jump to content

Postagens Recomendadas

A pergunta do título pode parecer boba. Como assim somar números? Adicionar números não é algo que fazemos já nos primeiros exercícios de programação?

A resposta poderá surpreendê-lo. 

Quando se trata de somar números inteiros, o resultado é bastante previsível. Vou dar alguns exemplos em Python e Javascript.

Em Javascript:

const a = 1;
const b = 2;
const c = a + b; // c = 3

Em Python:

a = 1
b = 2
c = a + b # c = 3

Até aí tudo bem. É a resposta que todo mundo conhece! Então onde está o problema? Pois bem.

E se o número for racional? No jargão da informática, e se o número for de ponto flutuante? Número com vírgula?

Aí as coisas ficam estranhas. Vamos ver um exemplo em Javascript:

const a = 0.1;
const b = 0.2;
const c = a + b; // c = 0.30000000000000004

Mas como assim? 

Como sabemos, os computadores representam informação - incluindo números - em base 2, ou seja, mesmo números com vírgula são convertidos para números binários ao serem processados. Mas essa conversão é perfeita? Não. Em especial, quando se trata de números de ponto flutuante, essa representação é aproximada. 

Isso pode levar a erros bastante sutis em nosso código. Tomemos como exemplo a seguinte comparação feita em Javascript:

const a = 0.1;
const b = 0.2;
const c = a + b; 

if (c == 0.3) {
  console.log("A soma é igual a 0.3!");
} else {
  console.log("A soma é diferente de 0.3!");
}

O que acontece ao rodarmos o código acima? Pelo que já vimos, a soma é 0.30000000000000004, então cairemos no else, imprimindo "A soma é diferente de 0.3! 

Isso seria um grande problema se estivéssemos, por exemplo, validando campos de uma nota fiscal. Há campos com tolerância R$ 0,01; outros campos precisam ter valores idênticos (por exemplo, o valor total dos itens tem de bater com o total da nota). Como proceder, então?

Há mais de uma maneira de lidar com esse problema. Falarei aqui de duas.

A primeira consiste em converter todos os números para inteiros, trabalhar com eles como inteiros e depois covertê-los de volta no final, pois a representação de inteiros não sofre do problema que vimos acima. Essa solução pode ser aplicada em linguagens tipadas que possuam o tipo inteiro (por exemplo, int do C, Integer do Delphi ou u8 do Rust). Para isso, não há segredo. Tomemos como exemplo o seguinte código em Rust:

fn main() {
    let a = 0.1;
    let b = 0.2;
	
    // converti cada número para inteiro após multiplicar por 100 
    // considerei que as entradas sempre seriam números com duas casas decimais
    let int_a = (a*100.0) as i64;
    let int_b = (b*100.0) as i64;

    // realizei a soma usando inteiros
    let int_c = int_a + int_b;
    
    // converti novamente para float e dividi por 100 para ter o resultado
    let result = int_c as f64/100.0;

    // ao realizar comparações, usei o resultado inteiro, não a versão em ponto flutuante!
    if int_c == 30 {
        println!("A soma é 0.3! O resultado é {}!", result);
    } else {
        println!("A soma não é 0.3! O resultado é {}!", result);
    }
}

Outra solução, que funciona para todas as linguagens, é verificar se o valor da diferença entre um número e outro é quase zero:

const a = 0.1;
const b = 0.2;
const c = a + b;
const epsilon = 1e-7;

if (c - 0.3 < epsilon) {
  console.log("A soma é igual a 0.3!");
} else {
  console.log("A soma é diferente de 0.3!");
}

A diferença eu chamei de epsilon, inspirando-me na implementação que se recomenda fazer no Rust, mas poderia ter qualquer outro nome que preferir. O importate é que seja um número relativamente pequeno, no caso 0,0000001.

O código acima, se rodado, retorna "A soma é igual a 0.3!" como desejado.

O mais conveniente é transformar a comparação numa função que retorne verdadeiro ou falso, evitando a duplicação de código e centralizando a lógica para números de ponto flutuante.

 

  • Curtir 2
Link to comment
Compartilhe em outros sites

Crie uma conta ou entre para comentar 😀

Você precisa ser um membro para deixar um comentário.

Crie a sua conta

Participe da nossa comunidade, crie sua conta.
É bem rápido!

Criar minha conta agora

Entrar

Você já tem uma conta?
Faça o login agora.

Entrar agora


×
×
  • Create New...