Pergunta

Eu posso citar três vantagens de se utilizar double (ou float) em vez de decimal:

  1. usa menos memória.
  2. Mais rápido porque as operações matemáticas de ponto flutuante são suportados nativamente pelo processadores.
  3. Pode representar uma maior gama de números.

Mas estas vantagens parecem aplicar-se apenas às operações de cálculo intensivo, tais como aqueles encontrados na modelagem de software. Claro, duplos não deve ser usado quando a precisão é necessária, tais como cálculos financeiros. Então, existem razões práticas para nunca escolher double (ou float) em vez de decimal em aplicações "normais"?

Editado para adicionar: Obrigado por todas as grandes respostas, eu aprendi com eles.

Uma outra questão: Algumas pessoas fez o ponto que dobra pode representar mais precisamente números reais. Quando declarou Gostaria de pensar que eles costumam representá-los com mais precisão também. Mas é uma verdadeira declaração de que a precisão pode diminuir (por vezes significativamente) quando as operações de ponto flutuante são executadas?

Foi útil?

Solução

Eu acho que você resumiu as vantagens muito bem. Está no entanto faltando um ponto. A decimal tipo só é mais precisa no que representa de base 10 números (por exemplo, aqueles utilizados em cálculos de moeda / financeiras). Em geral, a double tipo vai oferecer pelo menos tão grande precisão (alguém me corrija se eu estiver errado) e definitivamente maior velocidade para os números reais arbitrários. A conclusão é simples: quando se considera que a usar, sempre use double menos que você precisa a precisão base 10 que oferece decimal

.

Editar:

Quanto à sua adicional pergunta sobre a diminuição na precisão dos números de ponto flutuante após as operações, esta é uma questão um pouco mais sutil. Na verdade, precisão (eu uso o termo alternadamente para a exatidão aqui) irá diminuir de forma constante após cada operação é executada. Isto é devido a duas razões:

  1. o fato de que certos números (mais obviamente decimais) não pode ser verdadeiramente representados em forma de ponto flutuante
  2. erros de arredondamento ocorrer, assim como se você estivesse fazendo o cálculo com a mão. Ele depende muito do contexto (quantas operações você está executando) se esses erros são bastante significativa para justificar a pensar muito no entanto.

Em todos os casos, se você quiser comparar números dois de ponto flutuante que deve, em teoria, ser equivalente (mas foram chegaram usando cálculos diferentes), você precisa permitir um certo grau de tolerância (o quanto varia, mas é tipicamente muito pequena).

Para uma visão mais detalhada dos casos particulares em que erros de precisão podem ser introduzidos, consulte a seção Precisão do Wikipedia artigo . Finalmente, se você quer uma discussão séria em profundidade (e matemática) de números de ponto flutuante / operações a nível máquina, tente ler o artigo frequentemente citado O que cada cientista computador deve saber sobre Floating-Point Arithmetic .

Outras dicas

Você parece local com os benefícios de usar um tipo de ponto flutuante. I tendem a projetar para casas decimais em todos os casos, e contar com um profiler para me informar se as operações em decimal está causando gargalos ou slow-downs. Nesses casos, eu vou "down cast" para duplicar ou float, mas apenas fazê-lo internamente, e com cuidado tentar controlar a perda de precisão, limitando o número de dígitos significativos na operação matemática que está sendo executada.

Em geral, se o seu valor é transitório (não reutilizado), você está seguro usar um tipo de ponto flutuante. O verdadeiro problema com tipos de ponto flutuante é a três cenários seguintes.

  1. Você está agregando valores de ponto flutuante (no caso do composto erros de precisão que)
  2. Você constrói valores com base no valor de ponto flutuante (por exemplo, em um algoritmo recursivo)
  3. Você está fazendo matemática com uma grande número de dígitos significativos (por exemplo, 123456789.1 * .000000000000000987654321)

Editar

De acordo com a documentação de referência em C # decimais :

O decimal palavra-chave denota uma tipo de dados de 128 bits. Comparado com tipos de ponto flutuante, o tipo decimal tem uma precisão maior e um menor gama, o que o torna adequado para cálculos financeiros e monetários.

Assim, para esclarecer a minha afirmação acima:

I tendem a projetar para casas decimais em todos casos, e contar com um profiler para deixar -me saber se operações em decimal é causando gargalos ou slow-downs.

Só tenho alguma vez trabalhou em indústrias onde decimais são favoráveis. Se você está trabalhando em phsyics ou motores gráficos, é provavelmente muito mais benéfico para projetar para um tipo de ponto flutuante (float ou duplo).

Decimal não é infinitamente preciso (é impossível representar precisão infinita para não-integral, em um tipo de dados primitivo), mas é muito mais preciso do que o dobro:

  • decimais = 28-29 dígitos significativos
  • double = 15-16 dígitos significativos
  • flutuador = 7 dígitos significativos

EDIT 2

Em resposta a Konrad Rudolph 's comentário, item 1 (acima) é definitivamente correta. Agregação de imprecisão faz de facto composto. Veja o código abaixo para um exemplo:

private const float THREE_FIFTHS = 3f / 5f;
private const int ONE_MILLION = 1000000;

public static void Main(string[] args)
{
    Console.WriteLine("Three Fifths: {0}", THREE_FIFTHS.ToString("F10"));
    float asSingle = 0f;
    double asDouble = 0d;
    decimal asDecimal = 0M;

    for (int i = 0; i < ONE_MILLION; i++)
    {
        asSingle += THREE_FIFTHS;
        asDouble += THREE_FIFTHS;
        asDecimal += (decimal) THREE_FIFTHS;
    }
    Console.WriteLine("Six Hundred Thousand: {0:F10}", THREE_FIFTHS * ONE_MILLION);
    Console.WriteLine("Single: {0}", asSingle.ToString("F10"));
    Console.WriteLine("Double: {0}", asDouble.ToString("F10"));
    Console.WriteLine("Decimal: {0}", asDecimal.ToString("F10"));
    Console.ReadLine();
}

Isso gera o seguinte:

Three Fifths: 0.6000000000
Six Hundred Thousand: 600000.0000000000
Single: 599093.4000000000
Double: 599999.9999886850
Decimal: 600000.0000000000

Como você pode ver, mesmo que estamos adicionando a partir do mesmo constante fonte, os resultados da dupla é menos precisa (embora provavelmente vai rodada corretamente), e a bóia é muito menos preciso, até o ponto onde ele tem sido reduzido a apenas dois dígitos significativos.

Uso decimais para a base de 10 valores, por exemplo cálculos financeiros, como já foi sugerido.

Mas dupla é geralmente mais preciso para arbitrárias valores calculados.

Por exemplo, se você quiser calcular o peso de cada linha em uma carteira, usar a dupla como o resultado será mais quase somar 100%.

No exemplo a seguir, doubleResult está mais perto de 1 de decimalResult:

// Add one third + one third + one third with decimal
decimal decimalValue = 1M / 3M;
decimal decimalResult = decimalValue + decimalValue + decimalValue;
// Add one third + one third + one third with double
double doubleValue = 1D / 3D;
double doubleResult = doubleValue + doubleValue + doubleValue;

Então, novamente tomando o exemplo de uma carteira:

  • O valor de cada linha na carteira de mercado é um valor monetário e, provavelmente, seria melhor representado como decimal.

  • O peso de cada linha no portfólio (= Valor de Mercado / SUM (valor de mercado)) é geralmente melhor representado como dupla.

Use um casal ou uma bóia quando você não precisa de precisão, por exemplo, em um jogo de plataforma que eu escrevi, eu usei um float para armazenar as velocidades dos jogadores. Obviamente, eu não preciso de super precisão aqui porque eu finalmente volta para um Int para desenhar na tela.

Em alguns Contabilidade, considere a possibilidade de usar tipos integrais em vez ou em conjunto. Por exemplo, vamos dizer que as regras que operam sob exigir que cada cálculo resultado reporte com pelo menos 6 casas decimais e o resultado final será arredondado para o centavo mais próximo.

Um cálculo de 1 / 6th de US $ 100 yields $ 16,66666666666666 ..., então o valor levada adiante em uma planilha será de R $ 16,666667. Ambos dupla e decimal deve originar que o resultado com precisão a 6 casas decimais. No entanto, podemos evitar qualquer erro cumulativo através da realização o resultado para a frente como um inteiro 16666667. Cada posterior cálculo pode ser feito com a mesma precisão e levada adiante de forma semelhante. Continuando o exemplo, eu calcular o imposto sobre vendas Texas sobre esse montante (16666667 * 0,0825 = 1375000). Adicionando os dois (que é uma pequena planilha) 1.666.667 + 1.375.000 = 18041667. Movendo o ponto de volta decimal em nós dá 18,041667, ou US $ 18,04.

Embora este pequeno exemplo não iria produzir um erro cumulativo usando double ou decimal, é bastante fácil de mostrar casos em que simplesmente calcular o decimal de casal ou e levando adiante se acumularia erro significativo. Se as regras que operam sob exigem um número limitado de casas decimais, armazenar cada valor como um inteiro, multiplicando por 10 ^ (# exigido de casa decimal), e depois dividindo por 10 ^ (# necessário de casas decimais) para obter o real valor irá evitar qualquer erro cumulativo.

Em situações em que as fracções de moedas não ocorrem (por exemplo, uma máquina de venda automática), não há nenhuma razão para usar tipos não integrais de todo. Basta pensar nisso como tostões contados, não dólares. Eu vi código onde todos os cálculos envolvidos apenas alguns centavos inteiros, ainda uso de LED duplo a erros! Integer única matemática removido a questão. Assim, a minha resposta não convencional é que, quando possível, renunciar tanto de casal e decimal.

Se você precisar interrop binário com outras linguagens ou plataformas, então você pode precisar usar float ou double, que são padronizados.

Nota: este post é baseado em informações das capacidades do tipo decimal de http: // csharpindepth. com.br / artigos / general / Decimal.aspx e minha própria interpretação do que isso significa. Vou assumir Duplo é normal IEEE precisão dupla.

Nota 2:. Menor eo maior neste post reffer à magnitude do número

Pros de "decimal".

  • "decimal" pode representar exatamente os números que podem ser escritos como (suficientemente curto) frações decimais, dupla pode não. Isso é importante em livros financeiros e semelhantes onde é importante que os resultados correspondam exatamente o que um ser humano fazer os cálculos daria.
  • "decimal" tem uma mantissa muito maior do que "double". Isso significa que para valores dentro de sua faixa normalizada "decimal" vai ter uma precisão muito maior do que o dobro.

contras de decimal

  • Será muito mais lento (não tenho benchmarks, mas eu acho que pelo menos uma ordem de magnitude talvez mais), decimal não vai beneficiar de qualquer aceleração de hardware e aritmética em que vai exigir relativamente caro multiplicação / divisão por potências de 10 (que é muito mais caro do que a multiplicação e dividion por potências de 2) para coincidir com o expoente antes da adição / subtração e para trazer a volta expoente na gama após multiplicação / divisão.
  • decimal vai transbordar antes tha dupla vontade. decimal só podem representar números até ± 2 96 -1. Por comparação dupla pode representar números até cerca de ± 2 1024
  • decimal vai estouro negativo antes. Os menores números representáveis ??no decimal são ± 10 -28 . Por comparação dupla pode representar valores até 2 -149 (aproximadamente 10 -45 ) se os números subnromal são suportados e 2 -126 (aproximadamente 10 -38 ) se eles não são.
  • decimal ocupa o dobro da memória como dupla.

A minha opinião é que você deve usar como padrão para o uso de "decimal" para o trabalho de dinheiro e outros casos em cálculo de correspondência humana exatamente é importante e que você deve usar duplo uso como sua escolha padrão, o resto do tempo.

Use pontos flutuantes se você valoriza o desempenho ao longo correção.

Escolha o tipo em função da sua aplicação. Se você precisa de precisão como em análise financeira, de ter respondido a sua pergunta. Mas se o seu aplicativo pode se contentar com uma estimativa seu ok com o dobro.

É a sua aplicação na necessidade de um cálculo rápido ou ele vai ter todo o tempo do mundo para lhe dar uma resposta? Ela realmente depende do tipo de aplicação.

Graphic fome? flutuar ou dupla é suficiente. A análise de dados financeiros, meteoro atingindo um tipo planeta de precisão? Aqueles que precisam de um pouco de precisão:)

Decimal tem bytes mais amplos, duplo é suportado nativamente pelo CPU. Decimal é base-10, então uma conversão decimal-to-double está acontecendo enquanto um decimal é computado.

For accounting - decimal
For finance - double
For heavy computation - double

Tenha em mente .NET CLR suporta apenas Math.pow (double, double). Decimal não é suportado.

.NET Framework 4

[SecuritySafeCritical]
public static extern double Pow(double x, double y);
valores double

A serializará a notação científica por padrão se que a notação é mais curto do que a exibição decimal. (Por exemplo 0,00000003 será 3e-8) Os valores decimais jamais serializar a notação científica. Quando a serialização para o consumo por uma parte externa, isso pode ser uma consideração.

depende do que você precisa para isso.

Porque float e double são tipos de dados binários que você tem alguns diifculties e errrors na forma como os números rounds, então, por exemplo dupla faria rodada ,1-0,100000001490116, dupla faria também round 1/3 para 0,33333334326441. Simplesmente não colocar todos os números reais têm representação precisa em tipos duplas

Felizmente C # também suporta o chamado decimal aritmética de ponto flutuante, onde os números são representados através do sistema numérico decimal em vez do sistema binário. Assim, o decimal ponto flutuante-aritmética não perde precisão quando armazenar e processar números de ponto flutuante. Isso torna extremamente adequado para cálculos onde é necessário um alto nível de precisão.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top