Qual é a diferença entre decimal
, float
e double
em .NET?
Quando alguém usaria um desses?
Qual é a diferença entre decimal
, float
e double
em .NET?
Quando alguém usaria um desses?
Respostas:
float
e double
são tipos de pontos binários flutuantes . Em outras palavras, eles representam um número como este:
10001.10010110011
O número binário e a localização do ponto binário são ambos codificados no valor.
decimal
é um tipo de ponto decimal flutuante . Em outras palavras, eles representam um número como este:
12345.65789
Novamente, o número e a localização do ponto decimal são codificados no valor - é o que torna decimal
ainda um tipo de ponto flutuante em vez de um tipo de ponto fixo.
O importante a ser observado é que os humanos estão acostumados a representar não-inteiros em uma forma decimal e esperam resultados exatos em representações decimais; nem todos os números decimais são exatamente representáveis no ponto flutuante binário - 0,1, por exemplo -, portanto, se você usar um valor de ponto flutuante binário, obterá uma aproximação de 0,1. Você ainda obterá aproximações ao usar um ponto decimal flutuante - o resultado da divisão de 1 por 3 não pode ser exatamente representado, por exemplo.
Quanto ao que usar quando:
Para valores que são "decimais naturalmente exatos", é bom usar decimal
. Isso geralmente é adequado para qualquer conceito inventado por humanos: os valores financeiros são o exemplo mais óbvio, mas também existem outros. Considere a pontuação atribuída a mergulhadores ou patinadores no gelo, por exemplo.
Para valores que são mais artefactos da natureza que não pode realmente ser medidos exatamente de qualquer maneira, float
/ double
são mais apropriadas. Por exemplo, dados científicos geralmente seriam representados neste formulário. Aqui, os valores originais não serão "decimais precisos" para começar, portanto, não é importante que os resultados esperados mantenham a "precisão decimal". Os tipos de ponto binário flutuante são muito mais rápidos do que os decimais.
float
/ double
Geralmente não representam números como 101.101110
, normalmente ele é representado como algo como 1101010 * 2^(01010010)
- um expoente
float
é uma palavra-chave alias em C # e não é do tipo .Net. é System.Single
.. single
e double
são tipos de pontos binários flutuantes.
Precisão é a principal diferença.
Flutuador - 7 dígitos (32 bits)
Duplo -15-16 dígitos (64 bits)
Decimal -28-29 dígitos significativos (128 bits)
Os decimais têm uma precisão muito maior e geralmente são usados em aplicativos financeiros que exigem um alto grau de precisão. Os decimais são muito mais lentos (até 20 vezes mais em alguns testes) do que um double / float.
Decimais e Bóias / Dobros não podem ser comparados sem um elenco, enquanto Bóias e Dobros podem. Os decimais também permitem a codificação ou zeros à direita.
float flt = 1F/3;
double dbl = 1D/3;
decimal dcm = 1M/3;
Console.WriteLine("float: {0} double: {1} decimal: {2}", flt, dbl, dcm);
Resultado:
float: 0.3333333
double: 0.333333333333333
decimal: 0.3333333333333333333333333333
0.1
- isso raramente acontece no mundo real! Qualquer formato de armazenamento finito confunde um número infinito de valores possíveis com um número finito de padrões de bits. Por exemplo, float
conflitará 0.1
e 0.1 + 1e-8
, enquanto decimal
conflitará 0.1
e 0.1 + 1e-29
. Certamente, dentro de um determinado intervalo , certos valores podem ser representados em qualquer formato com perda zero de precisão (por exemplo, float
pode armazenar qualquer número inteiro até 1.6e7 com perda zero de precisão) - mas isso ainda não é precisão infinita .
0.1
é um valor especial ! A única coisa que torna 0.1
"melhor" do que 0.10000001
é porque os seres humanos gostam da base 10. E mesmo com um float
valor, se você inicializar dois valores 0.1
da mesma maneira, ambos terão o mesmo valor . Só que esse valor não será exatamente 0.1
- será o valor mais próximo do 0.1
que pode ser representado exatamente como afloat
. Claro, com flutuadores binários (1.0 / 10) * 10 != 1.0
, mas também com flutuadores decimais (1.0 / 3) * 3 != 1.0
. Nem é perfeitamente preciso.
double a = 0.1; double b = 0.1;
, a == b
será verdade . É apenas isso a
e ambos não b
serão exatamente iguais . Em C #, se você o fizer , também será verdadeiro. Mas, nesse caso, nem de nem será exatamente igual - ambos irão igual . Nos dois casos, alguma precisão é perdida devido à representação. Você teimosamente diz que tem precisão "infinita", o que é falso . 0.1
decimal a = 1.0m / 3.0m; decimal b = 1.0m / 3.0m;
a == b
a
b
1/3
0.3333...
decimal
A estrutura decimal é estritamente voltada para cálculos financeiros que exigem precisão, que são relativamente intolerantes ao arredondamento. Os decimais não são adequados para aplicações científicas, no entanto, por várias razões:
+---------+----------------+---------+----------+---------------------------------------------+
| C# | .Net Framework | Signed? | Bytes | Possible Values |
| Type | (System) type | | Occupied | |
+---------+----------------+---------+----------+---------------------------------------------+
| sbyte | System.Sbyte | Yes | 1 | -128 to 127 |
| short | System.Int16 | Yes | 2 | -32768 to 32767 |
| int | System.Int32 | Yes | 4 | -2147483648 to 2147483647 |
| long | System.Int64 | Yes | 8 | -9223372036854775808 to 9223372036854775807 |
| byte | System.Byte | No | 1 | 0 to 255 |
| ushort | System.Uint16 | No | 2 | 0 to 65535 |
| uint | System.UInt32 | No | 4 | 0 to 4294967295 |
| ulong | System.Uint64 | No | 8 | 0 to 18446744073709551615 |
| float | System.Single | Yes | 4 | Approximately ±1.5 x 10-45 to ±3.4 x 1038 |
| | | | | with 7 significant figures |
| double | System.Double | Yes | 8 | Approximately ±5.0 x 10-324 to ±1.7 x 10308 |
| | | | | with 15 or 16 significant figures |
| decimal | System.Decimal | Yes | 12 | Approximately ±1.0 x 10-28 to ±7.9 x 1028 |
| | | | | with 28 or 29 significant figures |
| char | System.Char | N/A | 2 | Any Unicode character (16 bit) |
| bool | System.Boolean | N/A | 1 / 2 | true or false |
+---------+----------------+---------+----------+---------------------------------------------+
Não reiterarei toneladas de informações boas (e ruins) já respondidas em outras respostas e comentários, mas responderei sua pergunta de acompanhamento com uma dica:
Quando alguém usaria um desses?
Use decimal para valores contados
Use float / double para valores medidos
Alguns exemplos:
dinheiro (contamos dinheiro ou medimos dinheiro?)
distance (contamos distância ou medimos distância? *)
pontuações (contamos pontuações ou medimos pontuações?)
Sempre contamos dinheiro e nunca devemos medi-lo. Normalmente medimos a distância. Contamos frequentemente pontuações.
* Em alguns casos, o que eu chamaria de distância nominal , podemos realmente querer 'contar' a distância. Por exemplo, talvez estejamos lidando com sinais de países que mostram distâncias para cidades e sabemos que essas distâncias nunca têm mais de um dígito decimal (xxx.x km).
float
7 dígitos de precisão
double
tem cerca de 15 dígitos de precisão
decimal
tem cerca de 28 dígitos de precisão
Se você precisar de uma precisão melhor, use duplo em vez de flutuar. Nas CPUs modernas, os dois tipos de dados têm quase o mesmo desempenho. O único benefício de usar float é que eles ocupam menos espaço. Praticamente importa apenas se você tiver muitos deles.
Achei isso interessante. O que todo cientista da computação deve saber sobre aritmética de ponto flutuante
double
adequado em aplicativos de contabilidade nesses casos (e basicamente apenas naqueles casos) em que nenhum tipo inteiro maior que 32 bits estava disponível, e double
estava sendo usado como se fosse um tipo inteiro de 53 bits (por exemplo, para manter um número inteiro de centavos ou um número inteiro de centésimos de centavo). Atualmente, não há muito uso para essas coisas, mas muitas linguagens ganharam a capacidade de usar valores de ponto flutuante de precisão dupla muito antes de ganharem matemática inteira de 64 bits (ou, em alguns casos, até 32 bits!).
Real
poderia representar valores de até 1,8E + 19 com precisão de unidade. Eu acho que seria muito mais saudável para uma aplicação de contabilidade de usar Real
para representar um número inteiro de moedas de um centavo do que ...
double
tipo com precisão de unidade de até 9E15. Se for necessário armazenar números inteiros maiores que o maior tipo inteiro disponível, o uso double
poderá ser mais simples e eficiente do que tentar falsificar a matemática de multiprecisão, especialmente porque os processadores têm instruções para executar 16x16-> 32 ou. ..
Ninguém mencionou isso
Nas configurações padrão, os flutuadores (System.Single) e os duplos (System.Double) nunca usarão a verificação de estouro, enquanto Decimal (System.Decimal) sempre usará a verificação de estouro.
Quero dizer
decimal myNumber = decimal.MaxValue;
myNumber += 1;
lança OverflowException .
Mas estes não:
float myNumber = float.MaxValue;
myNumber += 1;
&
double myNumber = double.MaxValue;
myNumber += 1;
float.MaxValue+1 == float.MaxValue
, assim como decimal.MaxValue+0.1D == decimal.MaxValue
. Talvez você quis dizer algo como float.MaxValue*2
?
System.Decimal
exceção é lançada pouco antes de se tornar incapaz de distinguir unidades inteiras, mas se um aplicativo supostamente estiver lidando com, por exemplo, dólares e centavos, isso pode ser tarde demais.
decimal
por zero (CS0020), e o mesmo se aplica aos literais integrais. No entanto, se um valor decimal em tempo de execução for dividido por zero, você receberá uma exceção e não um erro de compilação.
Inteiros, como foi mencionado, são números inteiros. Eles não podem armazenar algo do ponto, como 0,7, 0,42 e 0,007. Se você precisar armazenar números que não sejam números inteiros, precisará de um tipo diferente de variável. Você pode usar o tipo duplo ou flutuante. Você configura esses tipos de variáveis exatamente da mesma maneira: em vez de usar a palavra int
, você digita double
ou float
. Como isso:
float myFloat;
double myDouble;
( float
é a abreviação de "ponto flutuante" e significa apenas um número com um ponto no final.)
A diferença entre os dois está no tamanho dos números que eles podem conter. Para float
, você pode ter até 7 dígitos no seu número. Para double
s, você pode ter até 16 dígitos. Para ser mais preciso, eis o tamanho oficial:
float: 1.5 × 10^-45 to 3.4 × 10^38
double: 5.0 × 10^-324 to 1.7 × 10^308
float
é um número de 32 bits e double
é um número de 64 bits.
Clique duas vezes no seu novo botão para obter o código. Adicione as três linhas a seguir ao código do botão:
double myDouble;
myDouble = 0.007;
MessageBox.Show(myDouble.ToString());
Pare o seu programa e retorne à janela de codificação. Mude esta linha:
myDouble = 0.007;
myDouble = 12345678.1234567;
Execute seu programa e clique no botão duplo. A caixa de mensagem exibe corretamente o número. Adicione outro número no final, porém, e o C # será novamente arredondado para cima ou para baixo. A moral é que se você quer precisão, tenha cuidado ao arredondar!
decimal
é realmente armazenado no formato decimal (em oposição à base 2; portanto, não perde ou arredonda os dígitos devido à conversão entre os dois sistemas numéricos); além disso, decimal
não tem conceito de valores especiais como NaN, -0, ∞ ou -∞.
Esta tem sido uma discussão interessante para mim, pois hoje, tivemos apenas um bug desagradável, por decimal
ter menos precisão que a float
.
Em nosso código C #, estamos lendo valores numéricos de uma planilha do Excel, convertendo-os em um decimal
e enviando-os decimal
novamente para um Serviço para salvar em um banco de dados do SQL Server .
Microsoft.Office.Interop.Excel.Range cell = …
object cellValue = cell.Value2;
if (cellValue != null)
{
decimal value = 0;
Decimal.TryParse(cellValue.ToString(), out value);
}
Agora, para quase todos os nossos valores do Excel, isso funcionou perfeitamente. Mas, para alguns valores muito pequenos do Excel, o uso decimal.TryParse
do valor foi perdido completamente. Um exemplo é
cellValue = 0.00006317592
Decimal.TryParse (cellValue.ToString (), valor out); // retornaria 0
A solução, estranhamente, foi converter os valores do Excel em um double
primeiro e depois em um decimal
:
Microsoft.Office.Interop.Excel.Range cell = …
object cellValue = cell.Value2;
if (cellValue != null)
{
double valueDouble = 0;
double.TryParse(cellValue.ToString(), out valueDouble);
decimal value = (decimal) valueDouble;
…
}
Embora double
tenha menos precisão que a decimal
, isso realmente garantiu que pequenos números ainda seriam reconhecidos. Por alguma razão, double.TryParse
foi realmente capaz de recuperar números tão pequenos, enquanto decimal.TryParse
os definiria como zero.
Ímpar. Muito estranho.
decimal.Parse("0.00006317592")
funciona - você tem algo mais acontecendo. - Notação possivelmente científica?
Para aplicativos como jogos e sistemas incorporados nos quais a memória e o desempenho são críticos, o float geralmente é o tipo numérico de escolha, pois é mais rápido e tem a metade do tamanho de um dobro. Os números inteiros costumavam ser a arma preferida, mas o desempenho do ponto flutuante ultrapassou o número inteiro nos processadores modernos. Decimal está certo!
Os tipos de variável Decimal, Double e Float são diferentes na maneira como eles armazenam os valores. Precisão é a principal diferença em que float é um tipo de dados de ponto flutuante de precisão única (32 bits), double é um tipo de dados de ponto flutuante de precisão dupla (64 bits) e decimal é um tipo de dados de ponto flutuante de 128 bits.
Flutuador - 32 bits (7 dígitos)
Duplo - 64 bits (15-16 dígitos)
Decimal - 128 bits (28-29 dígitos significativos)
Mais sobre ... a diferença entre Decimal, Float e Double
O problema com todos esses tipos é que uma certa imprecisão subsiste E que esse problema pode ocorrer com pequenos números decimais, como no exemplo a seguir
Dim fMean as Double = 1.18
Dim fDelta as Double = 0.08
Dim fLimit as Double = 1.1
If fMean - fDelta < fLimit Then
bLower = True
Else
bLower = False
End If
Pergunta: Qual valor a variável bLower contém?
Resposta: Em uma máquina de 32 bits, o bLower contém VERDADEIRO !!!
Se substituir Double por Decimal, o bLower conterá FALSE, que é a boa resposta.
Em dobro, o problema é que fMean-fDelta = 1.09999999999 é menor que 1.1.
Cuidado: Eu acho que esse mesmo problema certamente pode existir para outro número, porque Decimal é apenas um duplo com maior precisão e a precisão sempre tem um limite.
De fato, Double, Float e Decimal correspondem ao decimal BINARY em COBOL!
É lamentável que outros tipos numéricos implementados no COBOL não existam no .Net. Para aqueles que não conhecem COBOL, existem em COBOL seguindo o tipo numérico
BINARY or COMP like float or double or decimal
PACKED-DECIMAL or COMP-3 (2 digit in 1 byte)
ZONED-DECIMAL (1 digit in 1 byte)
Em palavras simples:
/==========================================================================================
Type Bits Have up to Approximate Range
/==========================================================================================
float 32 7 digits -3.4 × 10 ^ (38) to +3.4 × 10 ^ (38)
double 64 15-16 digits ±5.0 × 10 ^ (-324) to ±1.7 × 10 ^ (308)
decimal 128 28-29 significant digits ±7.9 x 10 ^ (28) or (1 to 10 ^ (28)
/==========================================================================================
Você pode ler mais aqui , Flutuante , Duplo e Decimal .
Decimal
adequado para aplicações financeiras e é o principal critério a ser usado ao decidir entre Decimal
e Double
. É raro que a Double
precisão não seja suficiente para aplicações científicas, por exemplo (e Decimal
muitas vezes não é adequada para aplicações científicas devido ao seu alcance limitado).
A principal diferença entre cada um deles é a precisão.
float
é um 32-bit
número, double
é um 64-bit
número e decimal
é um 128-bit
número.
Decimal de 128 bits (28-29 dígitos significativos) No caso de aplicativos financeiros, é melhor usar os tipos decimais, pois fornece um alto nível de precisão e é fácil evitar erros de arredondamento. Use decimal para matemática não inteira onde a precisão é necessária (por exemplo, dinheiro e moeda)
Tipo duplo de 64 bits (15 a 16 dígitos) Os tipos duplos são provavelmente o tipo de dados mais usado para valores reais, exceto manipulando dinheiro. Use double para matemática não inteira, onde a resposta mais precisa não é necessária.
Flutuar 32 bits (7 dígitos) É usado principalmente em bibliotecas gráficas, porque demandas muito altas de capacidade de processamento também usavam situações que podem suportar erros de arredondamento.
Decimals
são muito mais lentos que um double/float
.
Decimals
e Floats/Doubles
não pode ser comparado sem um elenco enquanto Floats
e Doubles
pode.
Decimals
também permite a codificação ou zeros à direita.
você deve mencionar valores como:
Decimal dec = 12M/6;
Double dbl = 11D/6;
float fl = 15F/6;
e verifique os resultados.
Float - 4
Double - 8
Decimal - 12