Qual è la differenza tra decimal
, float
e double
in .NET?
Quando qualcuno userebbe uno di questi?
Qual è la differenza tra decimal
, float
e double
in .NET?
Quando qualcuno userebbe uno di questi?
Risposte:
float
e double
sono tipi di punti binari mobili . In altre parole, rappresentano un numero come questo:
10001.10010110011
Il numero binario e la posizione del punto binario sono entrambi codificati all'interno del valore.
decimal
è un tipo di virgola decimale mobile . In altre parole, rappresentano un numero come questo:
12345.65789
Ancora una volta, il numero e la posizione del punto decimale sono entrambi codificati all'interno del valore: questo è ciò che rende decimal
ancora un tipo a virgola mobile anziché un tipo a virgola fissa.
La cosa importante da notare è che gli umani sono abituati a rappresentare numeri non interi in una forma decimale e si aspettano risultati esatti in rappresentazioni decimali; non tutti i numeri decimali sono esattamente rappresentabili in virgola mobile binaria, ad esempio 0,1, quindi se si utilizza un valore in virgola mobile binaria si ottiene effettivamente un'approssimazione a 0,1. Otterrai comunque approssimazioni anche usando un punto decimale mobile, ad esempio il risultato della divisione 1 per 3 non può essere rappresentato esattamente.
Per quanto riguarda cosa usare quando:
Per valori che sono "decimali esatti per natura" è bene usarli decimal
. Questo di solito è adatto a qualsiasi concetto inventato dall'uomo: i valori finanziari sono l'esempio più ovvio, ma ce ne sono anche altri. Considera, ad esempio, il punteggio assegnato ai subacquei o ai pattinatori su ghiaccio.
Per i valori che sono più artefatti della natura che non possono essere misurati esattamente in ogni caso, float
/ double
sono più appropriati. Ad esempio, i dati scientifici sarebbero di solito rappresentati in questo modulo. Qui, i valori originali non saranno "decimalmente precisi" per cominciare, quindi non è importante che i risultati previsti mantengano la "precisione decimale". I tipi di punti binari mobili sono molto più veloci con i decimali.
float
/ di double
solito non rappresentano numeri come 101.101110
, normalmente è rappresentato come qualcosa del tipo 1101010 * 2^(01010010)
- un esponente
float
è una parola chiave alias C # e non è un tipo .Net. è System.Single
.. single
e double
sono tipi di punti binari mobili.
La precisione è la differenza principale.
Float - 7 cifre (32 bit)
Doppie -15-16 cifre (64 bit)
Decimali -28-29 cifre significative (128 bit)
I decimali hanno una precisione molto più elevata e vengono generalmente utilizzati all'interno di applicazioni finanziarie che richiedono un elevato grado di accuratezza. I decimali sono molto più lenti (fino a 20 volte volte in alcuni test) rispetto a un doppio / float.
Decimali e float / doppi non possono essere confrontati senza un cast, mentre i float e i doppi possono farlo. I decimali consentono anche la codifica o lo zero finale.
float flt = 1F/3;
double dbl = 1D/3;
decimal dcm = 1M/3;
Console.WriteLine("float: {0} double: {1} decimal: {2}", flt, dbl, dcm);
Risultato:
float: 0.3333333
double: 0.333333333333333
decimal: 0.3333333333333333333333333333
0.1
- questo è raramente il caso nel mondo reale! Qualsiasi formato di archiviazione finito configura un numero infinito di valori possibili in un numero finito di schemi di bit. Ad esempio, float
si confonderà 0.1
e 0.1 + 1e-8
, mentre decimal
si confonderà 0.1
e 0.1 + 1e-29
. Certo, entro un determinato intervallo , alcuni valori possono essere rappresentati in qualsiasi formato con perdita di precisione pari a zero (ad esempio, è float
possibile memorizzare qualsiasi numero intero fino a 1,6e7 con perdita di precisione pari a zero), ma questa non è ancora precisione infinita .
0.1
è un valore speciale ! L'unica cosa che rende 0.1
"migliore" di 0.10000001
è perché agli esseri umani piace la base 10. E anche con un float
valore, se si inizializzano due valori 0.1
allo stesso modo, entrambi avranno lo stesso valore . È solo che quel valore non sarà esattamente 0.1
- sarà il valore più vicino a 0.1
quello che può essere rappresentato esattamente comefloat
. Certo, con float binari (1.0 / 10) * 10 != 1.0
, ma anche con float decimali (1.0 / 3) * 3 != 1.0
. Nessuno dei due è perfettamente preciso.
double a = 0.1; double b = 0.1;
allora a == b
sarà vero . È solo questo a
e entrambi non b
saranno esattamente uguali . In C #, se lo fai, allora sarà anche vero. Ma in quel caso, né di né sarà esattamente uguale - entrambi saranno uguali . In entrambi i casi, la precisione viene persa a causa della rappresentazione. Dici testardamente che ha una precisione "infinita", che è falsa . 0.1
decimal a = 1.0m / 3.0m; decimal b = 1.0m / 3.0m;
a == b
a
b
1/3
0.3333...
decimal
La struttura decimale è strettamente orientata ai calcoli finanziari che richiedono precisione, che sono relativamente intolleranti all'arrotondamento. I decimali non sono adeguati per le applicazioni scientifiche, tuttavia, per diversi motivi:
+---------+----------------+---------+----------+---------------------------------------------+
| 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 |
+---------+----------------+---------+----------+---------------------------------------------+
Non ribadirò tonnellate di informazioni buone (e alcune cattive) già risposte in altre risposte e commenti, ma risponderò alla tua domanda di follow-up con un suggerimento:
Quando qualcuno userebbe uno di questi?
Usa i decimali per i valori conteggiati
Utilizzare float / double per i valori misurati
Qualche esempio:
denaro (contiamo i soldi o misuriamo i soldi?)
distanza (contiamo la distanza o misuriamo la distanza? *)
punteggi (contiamo i punteggi o misuriamo i punteggi?)
Contiamo sempre il denaro e non dovremmo mai misurarlo. Di solito misuriamo la distanza. Contiamo spesso i punteggi.
* In alcuni casi, ciò che definirei distanza nominale , potremmo davvero voler "contare" la distanza. Ad esempio, forse abbiamo a che fare con segni di paesi che mostrano le distanze dalle città e sappiamo che tali distanze non hanno mai più di una cifra decimale (xxx.x km).
float
7 cifre di precisione
double
ha circa 15 cifre di precisione
decimal
ha circa 28 cifre di precisione
Se hai bisogno di una maggiore precisione, usa double invece di float. Nelle CPU moderne entrambi i tipi di dati hanno quasi le stesse prestazioni. L'unico vantaggio dell'utilizzo di float è che occupano meno spazio. Praticamente conta solo se ne hai molti.
Ho trovato questo interessante. Ciò che ogni scienziato informatico dovrebbe sapere sull'aritmetica a virgola mobile
double
corretto nelle applicazioni di contabilità in quei casi (e fondamentalmente solo in quei casi) in cui non era disponibile alcun tipo intero maggiore di 32 bit e double
veniva utilizzato come se fosse un tipo intero a 53 bit (ad esempio per contenere un numero intero di centesimi o un numero intero di centesimi di centesimo). Oggigiorno non si usano molto per queste cose, ma molte lingue hanno acquisito la capacità di usare valori a virgola mobile a precisione doppia molto prima di guadagnare matematica a 64 bit (o in alcuni casi anche a 32 bit!).
Real
IIRC poteva rappresentare valori fino a 1,8E + 19 con precisione unitaria. Penso che sarebbe molto più sicuro che un'applicazione di contabilità utilizzasse Real
per rappresentare un numero intero di penny rispetto a ...
double
tipo con una precisione dell'unità fino a 9E15. Se uno ha bisogno di memorizzare numeri interi che sono più grandi del più grande tipo intero disponibile, usare double
è adatto per essere più semplice ed efficiente rispetto al tentativo di confondere la matematica multi-precisione, specialmente dato che mentre i processori hanno istruzioni per eseguire 16x16-> 32 o. ..
Nessuno lo ha menzionato
Nelle impostazioni predefinite, Floats (System.Single) e doppi (System.Double) non useranno mai il controllo di overflow mentre Decimal (System.Decimal) utilizzerà sempre il controllo di overflow.
intendo
decimal myNumber = decimal.MaxValue;
myNumber += 1;
genera OverflowException .
Ma questi non:
float myNumber = float.MaxValue;
myNumber += 1;
&
double myNumber = double.MaxValue;
myNumber += 1;
float.MaxValue+1 == float.MaxValue
, proprio come decimal.MaxValue+0.1D == decimal.MaxValue
. Forse intendevi qualcosa del genere float.MaxValue*2
?
System.Decimal
genera un'eccezione poco prima che diventi in grado di distinguere le unità intere, ma se si suppone una richiesta a che fare con ad es dollari e centesimi, che potrebbe essere troppo tardi.
decimal
per zero (CS0020), e lo stesso vale per i letterali integrali. Tuttavia, se un valore decimale di runtime è diviso per zero, otterrai un'eccezione non un errore di compilazione.
I numeri interi, come detto, sono numeri interi. Non possono memorizzare il punto qualcosa, come .7, .42 e .007. Se è necessario memorizzare numeri che non sono numeri interi, è necessario un diverso tipo di variabile. È possibile utilizzare il tipo doppio o il tipo float. Puoi impostare questi tipi di variabili esattamente nello stesso modo: invece di usare la parola int
, digiti double
o float
. Come questo:
float myFloat;
double myDouble;
(float
è l'abbreviazione di "virgola mobile" e significa solo un numero con un punto alla fine.)
La differenza tra i due sta nella dimensione dei numeri che possono contenere. Per float
, puoi avere fino a 7 cifre nel tuo numero. Per double
s, puoi avere fino a 16 cifre. Per essere più precisi, ecco la dimensione ufficiale:
float: 1.5 × 10^-45 to 3.4 × 10^38
double: 5.0 × 10^-324 to 1.7 × 10^308
float
è un numero a 32 bit e double
è un numero a 64 bit.
Fare doppio clic sul nuovo pulsante per accedere al codice. Aggiungi le tre righe seguenti al codice del tuo pulsante:
double myDouble;
myDouble = 0.007;
MessageBox.Show(myDouble.ToString());
Arrestare il programma e tornare alla finestra di codifica. Cambia questa riga:
myDouble = 0.007;
myDouble = 12345678.1234567;
Esegui il programma e fai clic sul doppio pulsante. La finestra di messaggio visualizza correttamente il numero. Aggiungi un altro numero alla fine, tuttavia, e C # arrotolerà nuovamente verso l'alto o verso il basso. La morale è se vuoi la precisione, stai attento a arrotondare!
decimal
è effettivamente memorizzato in formato decimale (rispetto alla base 2; quindi non perderà o arrotonderà le cifre a causa della conversione tra i due sistemi numerici); inoltre, decimal
non ha alcun concetto di valori speciali come NaN, -0, ∞ o -∞.
Questo è stato un thread interessante per me, dato che oggi abbiamo appena avuto un brutto bug, per quanto riguarda decimal
avere meno precisione di un float
.
Nel nostro codice C #, stiamo leggendo valori numerici da un foglio di calcolo Excel, li convertiamo in un decimal
, quindi li rispediamo decimal
a un servizio per salvarli in un database di SQL Server .
Microsoft.Office.Interop.Excel.Range cell = …
object cellValue = cell.Value2;
if (cellValue != null)
{
decimal value = 0;
Decimal.TryParse(cellValue.ToString(), out value);
}
Ora, per quasi tutti i nostri valori di Excel, ha funzionato magnificamente. Ma per alcuni valori di Excel molto piccoli, l'utilizzo ha decimal.TryParse
perso completamente il valore. Un esempio è
cellValue = 0,00006317592
Decimal.TryParse (cellValue.ToString (), valore out); // restituirebbe 0
La soluzione, stranamente, era convertire i valori di Excel in un double
primo e poi in un 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;
…
}
Anche se double
ha meno precisione di un decimal
, questo in realtà assicura che piccoli numeri saranno comunque riconosciuti. Per qualche motivo, è double.TryParse
stato effettivamente in grado di recuperare numeri così piccoli, mentre decimal.TryParse
li avrebbe impostati a zero.
Dispari. Molto strano.
decimal.Parse("0.00006317592")
funziona - hai qualcosa da fare. - Forse notazione scientifica?
Per applicazioni come giochi e sistemi embedded in cui memoria e prestazioni sono entrambi fondamentali, il float è in genere il tipo di scelta numerica in quanto è più veloce e la metà delle dimensioni di un doppio. I numeri interi erano l'arma preferita, ma le prestazioni in virgola mobile hanno superato i numeri interi nei processori moderni. Decimale è subito!
I tipi di variabili Decimal, Double e Float sono diversi nel modo in cui memorizzano i valori. La precisione è la principale differenza in cui float è un tipo di dati a virgola mobile a precisione singola (32 bit), double è un tipo di dati a virgola mobile a precisione doppia (64 bit) e decimale è un tipo di dati a virgola mobile a 128 bit.
Float - 32 bit (7 cifre)
Doppio - 64 bit (15-16 cifre)
Decimale - 128 bit (28-29 cifre significative)
Maggiori informazioni su ... la differenza tra Decimale, Virgola mobile e Doppio
Il problema con tutti questi tipi è che sussiste una certa imprecisione E che questo problema può verificarsi con piccoli numeri decimali come nell'esempio seguente
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
Domanda: quale valore contiene la variabile bLower?
Risposta: su una macchina a 32 bit bLower contiene TRUE !!!
Se sostituisco Double con Decimal, bLower contiene FALSE che è la buona risposta.
In doppio, il problema è che fMean-fDelta = 1.09999999999 che è inferiore a 1.1.
Attenzione: penso che lo stesso problema possa certamente esistere per un altro numero perché Decimale è solo un doppio con maggiore precisione e la precisione ha sempre un limite.
In effetti, Double, Float e Decimal corrispondono al decimale BINARY in COBOL!
È deplorevole che altri tipi numerici implementati in COBOL non esistano in .Net. Per coloro che non conoscono COBOL, in COBOL esiste il seguente tipo numerico
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)
In parole semplici:
/==========================================================================================
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)
/==========================================================================================
Puoi leggere di più qui , Float , Double e Decimal .
Decimal
adatto per le applicazioni finanziarie ed è il criterio principale da utilizzare quando si decide tra Decimal
e Double
. È raro che la Double
precisione non sia sufficiente per applicazioni scientifiche, ad esempio (ed Decimal
è spesso inadatta per applicazioni scientifiche a causa della sua portata limitata).
La principale differenza tra ciascuno di questi è la precisione.
float
è un 32-bit
numero, double
è un 64-bit
numero ed decimal
è un 128-bit
numero.
Decimale 128 bit (28-29 cifre significative) In caso di applicazioni finanziarie è meglio usare i tipi decimali perché offre un alto livello di accuratezza e facile da evitare errori di arrotondamento Utilizzare decimale per la matematica non intera dove è necessaria la precisione (ad es. denaro e valuta)
Doppio 64 bit (15-16 cifre) I doppi tipi sono probabilmente il tipo di dati più comunemente usato per valori reali, ad eccezione della gestione del denaro. Usa double per la matematica non intera dove non è necessaria la risposta più precisa.
Float a 32 bit (7 cifre) Viene utilizzato principalmente nelle librerie grafiche perché richieste molto elevate di potenza di elaborazione, utilizza anche situazioni che possono sopportare errori di arrotondamento.
Decimals
sono molto più lenti di a double/float
.
Decimals
e Floats/Doubles
non può essere paragonato senza un cast mentre Floats
e Doubles
può.
Decimals
consentire anche la codifica o gli zeri finali.
devi menzionare i valori come:
Decimal dec = 12M/6;
Double dbl = 11D/6;
float fl = 15F/6;
e controlla i risultati.
Float - 4
Double - 8
Decimal - 12