C#

6 jun, 2018

C# – Usando o ponto flutuante nos cálculos

Publicidade

Neste artigo vou rever conceitos básicos do C# apresentando o tratamento de variáveis do tipo ponto flutuante em cálculos.

As limitações de uma variável do tipo int podem ser inaceitáveis para alguns tipos de aplicações. O intervalo em geral não é um problema; o intervalo de dois milhões de bits de um inteiro de 64 bits deve ser suficiente para a maioria dos problemas envolvendo inteiros.

No entanto, o fato de um int estar limitado à números inteiros pode ser o fator determinante na sua não utilização em muitos cenários. Em alguns casos, você precisa de números que podem ter uma parte fracionária diferente de zero. Esses números podem ser representados pelos números reais.

Na linguagem C#, os números reais podem ser de ponto flutuante e decimal, onde o ponto flutuante é o tipo mais comum.

Para declarar uma variável como sendo um número de ponto flutuante, podemos usar os tipos float e double na linguagem C#. (temos também o tipo decimal).

A tabela a seguir mostra a precisão e os intervalos aproximados dos tipos de ponto flutuante: para float e double.

Se você estiver pensando que float é o tipo padrão para os número de ponto flutuante, se enganou; o tipo padrão para estes números é double.

Assim, se você não declarar o tipo de uma variável, o C# vai inferir como double. Veja:

Tratando a precisão do resultado com ponto flutuante

A coluna “Precisão” na tabela acima refere-se ao número de dígitos significativos que esse tipo de variável pode representar.

Por exemplo, o número 0.555… possui uma sequência interminável de cincos (uma dízima periódica simples).

No entanto, uma variável do tipo float possui de 6 a 7 dígitos significativos de precisão, o que significa que números após o sexto dígito serão ignorados.

Veja o resultado obtido da divisão de 5/9 que nos dá o número 0,5555556 com 7 dígitos significativos quando usamos o tipo float.

Agora vejamos como fica se usarmos o tipo double para representar o mesmo resultado:

Agora vemos que o resultado é expresso com uma precisão de 15 dígitos: 0,555555555555556

A lição aprendida aqui, é que você deve usar variáveis do tipo double para representar números reais quando a precisão do cálculo for relevante, a menos que você tenha uma razão específica para não fazer isso.

Tomando cuidado ao fazer cálculos financeiros com ponto flutuante

Ao tratar com números de ponto flutuante e usar os tipos float e double, você tem que tomar muito cuidado com o resultado obtido em cálculos.

Veja esse exemplo:

1 – Vamos supor que o preço de um produto é R$ 4,99 e você deseja saber o valor total de 17 itens desse produto.

Abaixo, temos o código usado para fazer o cálculo usando o tipo float para o preço do produto e naturalmente você vai esperar o resultado de R$ 84,83 visto que 4.99×17 = 84.83. Certo?

Você esperava 84,83, mas o resultado obtido foi 84,82999. Para obter o resultado correto, você deve usar o tipo decimal.

Agora veja esse outro exemplo:

2 – Você vende um produto que custa R$ 100,00 e você esta dando um desconto de 10% sobre o valor do produto.

Abaixo, temos o código que calcula o valor final do produto com desconto usando o tipo float para desconto e int para o preço final visto que seu preço é inteiro.

Note que o valor esperado seria 90, mas você obteve 89. Seus clientes devem ficar muito felizes com esse 1% a mais de desconto.

Para obter o valor correto, use: decimal precoFinalComDesconto = (decimal)(precoProduto * (1 – desconto));

Conclusão

Para qualquer cálculo que envolva dinheiro ou finanças, o tipo Decimal deve ser sempre utilizado. Só este tipo tem a precisão adequada para evitar os erros críticos de arredondamento.

Por que?

O tipo de dados Decimal é simplesmente um tipo de ponto flutuante que é representado internamente como base 10 ao invés de base dois. Obviamente, com base 10 (o nosso sistema de numeração real) qualquer número decimal pode ser construído para o valor exato ter que realizar aproximações.

O tipo Decimal é realmente uma estrutura que contém funções sobrecarregadas para todas as operações matemáticas e de comparação, ou seja, ele é realmente uma implementação da aritmética de base 10.

E estamos conversados!