.Net - Float(Single), Double e Decimal. Afinal qual devo usar ?


Decidir qual o tipo de ponto flutuante usar vai depender da aplicação, mas aqui estão alguns considerações que podem ajudar a decidir:

Os tipos de dados FLOAT, DOUBLE e DECIMAL são usados para armazenar números reais até uma certa precisão.

Qual a diferença entre esses tipos então ?

A tabela abaixo compara o intervalo, precisão, maior inteiro e tamanho:

Tipo Intervalo Precisão(Digitos) Maior Inteiro
Exato
Tamanho
Float 1.5x10^-45 / 3.4x10^38 7 2^24 4 bytes
Double 5.0x10^-324 / 1.7x10^308 15-16 2^53 8 bytes
Decimal 1.0x10^-28 / 7.9x10^28 28-29 2^113 16 bytes

Obs: Maior inteiro exato significa o maior valor inteiro que pode ser representado sem perda de precisão. Estes valores devem ser mantidos em mente quando você está convertendo entre tipos inteiros e ponto flutuante.

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 quê ?

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.

Considere o código abaixo feito na linguagem C# em uma aplicação Console: (Feita no Visual C# 2010 Express Editions)

using System;

namespace Macoratti
{
    class Program
    {
        static void Main(string[] args)
        {
            int numero_iteracoes = 1;
            Console.WriteLine("Primeiro laço, usando o tipo float :");

            // executa somente 4 vezes e não 5 como esperado
            for (float d = 1.1f; d <= 1.5f; d += 0.1f)
            {
                Console.WriteLine("Iteração #: {0}, valor float : {1}", numero_iteracoes++, d.ToString("e10"));
            }

            Console.WriteLine("\r\nSegundo laço, usando o tipo Decimal :");
            // reseta o contador
            numero_iteracoes = 1;

            // executa corretamente para 5 interações
            for (Decimal d = 1.1m; d <= 1.5m; d += 0.1m)
            {
                Console.WriteLine("Iteração #: {0}, valor Decimal : {1}", numero_iteracoes++, d.ToString("e10"));
            }

            Console.WriteLine("Pressione algo para continuar..");
          Console.ReadKey();
        }
    }
}

Note que o primeiro laço é executado 4 vezes e não 5 como se esperava.

É por isso que o segundo laço for() é executado 5 vezes como esperado e a variável "d" do tipo Decimal tem sempre o valor exato atribuída a ela.

Considerações para o VB .NET (Float -> Single)

Para o VB .NET o equivalente ao tipo de dados Float da linguagem C# é o tipo da dados Single.

O tipo de dados Single armazena números de ponto flutuante de precisão simples assinados com IEEE de 32 bits e variando do valor de - 3.4028235E + 38 até -1.401298E - 45 para valores negativos e de 1.401298E - 45 a 3.4028235E + 38 para valores positivos. Números de precisão simples armazenam uma aproximação de um número real.

Use o tipo de dado Single para armazenar valores inteiros que não necessitam de todos os bits de um Double. Em alguns casos a commom language runtime(CLR) pode ser suficiente para armazenar suas variáveis do tipo Single próximas uma da outra e diminuir o uso de memória.

A versão do exemplo para o VB .NET em uma aplicação do tipo Console Application é vista abaixo:

Imports System.Threading.Interlocked
Imports System.Math

Module Module1

    Sub Main()
        Dim numero_iteracoes As Integer = 1
        Console.WriteLine("Preimeiro laço, usando o tipo float :")

        ' executa somente 4 vezes e não 5 como esperado
        Dim d0 As Single = 1.1F
        While d0 <= 1.5F
            Console.WriteLine("Iteração #: {0}, valor float : {1}", Max(Increment(numero_iteracoes), numero_iteracoes - 1), d0.ToString("e10"))
            d0 += 0.1F
        End While

        Console.WriteLine(vbCr & vbLf & "Segundo laço, usando o tipo Decimal :")
        ' reseta o contador
        numero_iteracoes = 1

        ' executa corretamente para 5 interações
        Dim d1 As Decimal = 1.1D
        While d1 <= 1.5D
            Console.WriteLine("Iteração #: {0}, valor Decimal : {1}", Max(Increment(numero_iteracoes), numero_iteracoes - 1), d1.ToString("e10"))
            d1 += 0.1D
        End While

        Console.WriteLine("Pressione algo para continuar..")
        Console.ReadKey()
    End Sub

End Module

As considerações feitas valem tanto para o VB .NET como para o C#.

Ts 2:1 Porque vós mesmos sabeis, irmãos, que a nossa entrada entre vós não foi vã;

1Ts 2:2 mas, havendo anteriormente padecido e sido maltratados em Filipos, como sabeis, tivemos a confiança em nosso Deus para vos falar o evangelho de Deus em meio de grande combate.

1Ts 2:3 Porque a nossa exortação não procede de erro, nem de imundícia, nem é feita com dolo;

1Ts 2:4 mas, assim como fomos aprovados por Deus para que o evangelho nos fosse confiado, assim falamos, não para agradar aos homens, mas a Deus, que prova os nossos corações.

Referências:


José Carlos Macoratti