Domanda

Posso citare tre vantaggi nell'uso di double (o float ) anziché decimale :

  1. Utilizza meno memoria.
  2. Più veloce perché le operazioni matematiche in virgola mobile sono supportate nativamente dai processori.
  3. Può rappresentare un intervallo più ampio di numeri.

Ma questi vantaggi sembrano applicarsi solo alle operazioni ad alta intensità di calcolo, come quelle che si trovano nel software di modellazione. Naturalmente, i doppi non dovrebbero essere usati quando è richiesta la precisione, come i calcoli finanziari. Quindi ci sono dei motivi pratici per scegliere mai double (o float ) invece di decimale in " normale " applicazioni?

Modificato per aggiungere: Grazie per tutte le ottime risposte, ho imparato da loro.

Un'ulteriore domanda: alcune persone hanno sottolineato che i doppi possono rappresentare più precisamente i numeri reali. Quando dichiarato, penso che di solito li rappresentano anche in modo più accurato. Ma è una vera affermazione che l'accuratezza può diminuire (a volte in modo significativo) quando vengono eseguite operazioni in virgola mobile?

È stato utile?

Soluzione

Penso che tu abbia riassunto abbastanza bene i vantaggi. Ti manca comunque un punto. Il tipo decimal è solo più preciso nel rappresentare i numeri base 10 (ad esempio quelli utilizzati nei calcoli valutari / finanziari). In generale, il tipo double offrirà almeno una grande precisione (qualcuno mi correggerà se sbaglio) e una velocità decisamente maggiore per numeri reali arbitrari. La semplice conclusione è: quando si considera quale utilizzare, utilizzare sempre double a meno che non sia necessaria la precisione base 10 che offre decimale .

Modifica

Per quanto riguarda la tua ulteriore domanda sulla diminuzione della precisione dei numeri in virgola mobile dopo le operazioni, questo è un problema leggermente più sottile. In effetti, la precisione (uso il termine in modo intercambiabile per accuratezza qui) diminuirà costantemente dopo l'esecuzione di ciascuna operazione. Ciò è dovuto a due motivi:

  1. il fatto che determinati numeri (ovviamente i decimali) non possono essere realmente rappresentati in virgola mobile
  2. si verificano errori di arrotondamento, proprio come se stessi facendo il calcolo a mano. Dipende molto dal contesto (quante operazioni stai eseguendo) se questi errori sono abbastanza significativi da giustificare molta riflessione.

In tutti i casi, se si desidera confrontare due numeri in virgola mobile che in teoria dovrebbero essere equivalenti (ma sono stati raggiunti usando calcoli diversi), è necessario consentire un certo grado di tolleranza (quanto varia, ma in genere è molto piccolo).

Per una panoramica più dettagliata dei casi particolari in cui è possibile introdurre errori di precisione, consultare la sezione Precisione di articolo di Wikipedia . Infine, se desideri una discussione seriamente approfondita (e matematica) dei numeri / operazioni in virgola mobile a livello di macchina, prova a leggere l'articolo spesso citato Ciò che ogni scienziato informatico dovrebbe sapere sull'aritmetica in virgola mobile .

Altri suggerimenti

Sembri perfetto con i vantaggi dell'utilizzo di un tipo a virgola mobile. Tendo a progettare decimali in tutti i casi e mi affido a un profiler per farmi sapere se le operazioni sui decimali stanno causando colli di bottiglia o rallentamenti. In questi casi, "lancerò giù". raddoppiare o fluttuare, ma farlo solo internamente e provare attentamente a gestire la perdita di precisione limitando il numero di cifre significative nell'operazione matematica eseguita.

In generale, se il tuo valore è temporaneo (non riutilizzato), sei sicuro di usare un tipo a virgola mobile. Il vero problema con i tipi in virgola mobile sono i seguenti tre scenari.

  1. Stai aggregando valori in virgola mobile (nel qual caso gli errori di precisione sono composti)
  2. Costruisci valori in base al valore in virgola mobile (ad esempio in un algoritmo ricorsivo)
  3. Stai facendo matematica con un numero molto ampio di cifre significative (ad esempio, 123456789.1 * .000000000000000987654321 )

Modifica

Secondo la documentazione di riferimento sui decimali C # :

  

La parola chiave decimale indica a   Tipo di dati a 128 bit. Rispetto a   tipi in virgola mobile, il tipo decimale   ha una maggiore precisione e una più piccola   gamma, che lo rende adatto per   calcoli finanziari e monetari.

Quindi, per chiarire la mia affermazione di cui sopra:

  

Tendo a progettare decimali in tutto   casi, e fare affidamento su un profiler per lasciare   so se le operazioni sul decimale sono   causando colli di bottiglia o rallentamenti.

Ho sempre lavorato in settori in cui i decimali sono favorevoli. Se stai lavorando su motori fisici o grafici, probabilmente è molto più vantaggioso progettare per un tipo a virgola mobile (float o double).

Il decimale non è infinitamente preciso (è impossibile rappresentare una precisione infinita per il non integrale in un tipo di dati primitivo), ma è molto più preciso del doppio:

  • decimale = 28-29 cifre significative
  • doppio = 15-16 cifre significative
  • float = 7 cifre significative

MODIFICA 2

In risposta al commento di Konrad Rudolph , l'articolo # 1 (sopra) è decisamente corretto. L'aggregazione dell'imprecisione in effetti aggrava. Vedi il codice sotto per un esempio:

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();
}

Questo genera quanto segue:

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

Come puoi vedere, anche se stiamo aggiungendo dalla stessa costante sorgente, i risultati del doppio sono meno precisi (anche se probabilmente si arrotonderanno correttamente) e il float è molto meno preciso, al punto in cui è stato ridotto a solo due cifre significative.

Usa i decimali per i valori di base 10, ad es. calcoli finanziari, come altri hanno suggerito.

Ma il doppio è generalmente più preciso per valori calcolati arbitrari.

Ad esempio, se si desidera calcolare il peso di ciascuna linea in un portafoglio, utilizzare il doppio in quanto il risultato si sommerà quasi fino al 100%.

Nel seguente esempio, doubleResult è più vicino a 1 di 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;

Riprendendo quindi l'esempio di un portafoglio:

  • Il valore di mercato di ogni riga del portafoglio è un valore monetario e probabilmente sarebbe meglio rappresentato come decimale.

  • Il peso di ciascuna riga del portafoglio (= Valore di mercato / SUM (Valore di mercato)) è generalmente meglio rappresentato come doppio.

Usa un double o un float quando non hai bisogno di precisione, ad esempio, in un gioco platform che ho scritto, ho usato un float per memorizzare le velocità del giocatore. Ovviamente non ho bisogno di super precisione qui perché alla fine mi rivolgo a un Int per disegnare sullo schermo.

In alcuni Contabilità, considerare la possibilità di utilizzare tipi integrali invece o congiuntamente. Ad esempio, supponiamo che le regole in base alle quali operi richiedano ogni risultato di calcolo riportato con almeno 6 decimali e il risultato finale verrà arrotondato al penny più vicino.

Un calcolo di 1/6 di $ 100 produce $ 16.66666666666666 ..., quindi il valore effettuato in un foglio di lavoro sarà $ 16.666667. Sia il doppio che il decimale dovrebbero produrre quel risultato con precisione a 6 decimali. Tuttavia, possiamo evitare qualsiasi errore cumulativo portando avanti il ??risultato come un numero intero 16666667. Ogni calcolo successivo può essere eseguito con la stessa precisione e portato avanti in modo simile. Continuando l'esempio, calcolo l'imposta sulle vendite in Texas su tale importo (16666667 * .0825 = 1375000). Aggiungendo i due (è un foglio di lavoro breve) 1666667 + 1375000 = 18041667. Spostare indietro il punto decimale ci dà 18,041667, o $ 18,04.

Anche se questo breve esempio non produrrebbe un errore cumulativo usando il doppio o il decimale, è abbastanza facile mostrare casi in cui il semplice calcolo del doppio o decimale e il proseguimento accumulerebbe un errore significativo. Se le regole in base alle quali operi richiedono un numero limitato di posizioni decimali, memorizzando ciascun valore come numero intero moltiplicando per 10 ^ (numero richiesto di posizione decimale) e quindi dividendo per 10 ^ (richiesto # numero di posizioni decimali) per ottenere l'effettivo valore eviterà qualsiasi errore cumulativo.

In situazioni in cui non si verificano frazioni di centesimi (ad esempio un distributore automatico), non vi è alcun motivo per utilizzare tipi non integrali. Pensa semplicemente a contare i penny, non i dollari. Ho visto codice in cui ogni calcolo riguardava solo interi centesimi, ma l'uso del doppio ha portato a errori! Integer solo la matematica ha rimosso il problema. Quindi la mia risposta non convenzionale è, quando possibile, rinunciare sia al doppio che al decimale.

Se è necessario eseguire l'interrop binaria con altre lingue o piattaforme, potrebbe essere necessario utilizzare float o double, che sono standardizzati.

Nota: questo post si basa sulle informazioni sulle capacità del tipo decimale da http: // csharpindepth. it / Articles / General / Decimal.aspx e la mia interpretazione di ciò che significa. Presumo che Double sia una normale doppia precisione IEEE.

Nota2: il più piccolo e il più grande in questo post si riferisce all'entità del numero.

Pro di " decimale " ;.

  • " decimale " può rappresentare esattamente numeri che possono essere scritti come frazioni decimali (sufficientemente brevi), doppio non può. Ciò è importante nei registri finanziari e simili dove è importante che i risultati corrispondano esattamente a ciò che darebbe un umano facendo i calcoli.
  • " decimale " ha una mantissa molto più grande di "doppia". Ciò significa che per i valori all'interno del suo intervallo normalizzato "decimale" avrà una precisione molto più elevata rispetto al doppio.

Contro del decimale

  • Sarà molto più lento (non ho benchmark ma immagino almeno un ordine di grandezza forse più), il decimale non trarrà beneficio da alcuna accelerazione hardware e l'aritmetica su di esso richiederà una moltiplicazione / divisione relativamente costosa per potere di 10 (che è molto più costoso della moltiplicazione e della divisione per poteri di 2) per abbinare l'esponente prima dell'addizione / sottrazione e per riportare l'esponente nel suo intervallo dopo la moltiplicazione / divisione.
  • il decimale traboccerà prima del doppio. il decimale può rappresentare solo numeri fino a & # 177; 2 96 -1. In confronto, il doppio può rappresentare numeri fino a quasi & # 177; 2 1024
  • il decimale effettuerà il underflow in precedenza. I numeri più piccoli rappresentabili in decimale sono & # 177; 10 -28 . Per confronto il doppio può rappresentare valori fino a 2 -149 (circa 10 -45 ) se sono supportati numeri subnromici e 2 -126 (circa 10 -38 ) se non lo sono.
  • decimale occupa il doppio della memoria rispetto al doppio.

La mia opinione è che dovresti utilizzare per impostazione predefinita " decimale " per lavoro monetario e altri casi in cui la corrispondenza del calcolo umano è esattamente importante e che dovresti usare il doppio come opzione predefinita per il resto del tempo.

Usa i punti mobili se dai valore alla correttezza.

Scegli il tipo in funzione della tua applicazione. Se hai bisogno di precisione come nell'analisi finanziaria, hai risposto alla tua domanda. Ma se la tua applicazione può accontentarsi di una stima, ok con doppio.

La tua richiesta ha bisogno di un calcolo veloce o avrà tutto il tempo per darti una risposta? Dipende molto dal tipo di applicazione.

Grafica affamata? float o double è abbastanza. Analisi dei dati finanziari, meteorite che colpisce un tipo di precisione del pianeta? Quelli avrebbero bisogno di un po 'di precisione :)

Il decimale ha byte più ampi, il doppio è supportato nativamente dalla CPU. Il decimale è base-10, quindi una conversione da decimale a doppia sta avvenendo mentre viene calcolato un decimale.

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

Tieni presente che .NET CLR supporta solo Math.Pow (doppio, doppio). Il decimale non è supportato.

.NET Framework 4

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

Un doppio valore verrà serializzato sulla notazione scientifica per impostazione predefinita se tale notazione è più corta della visualizzazione decimale. (ad es. 00000003 sarà 3e-8) I valori decimali non verranno mai serializzati sulla notazione scientifica. Quando si serializza per il consumo da una parte esterna, questa può essere una considerazione.

Dipende da cosa ti serve.

Poiché float e double sono tipi di dati binari, hai some diifculty ed errori nel modo in numeri di arrotondamenti, quindi ad esempio double arrotonderebbe da 0,1 a 0,100000001490116, double sarebbe arrotondare anche da 1/3 a 0,33333334326441. In poche parole, non tutti i numeri reali hanno una rappresentazione accurata in doppi tipi

Fortunatamente C # supporta anche la cosiddetta aritmetica decimale in virgola mobile, in cui i numeri sono rappresentati tramite il sistema numerico decimale piuttosto che il sistema binario. Pertanto, l'aritmetica decimale in virgola mobile non perde accuratezza durante la memorizzazione e l'elaborazione di numeri in virgola mobile. Ciò lo rende immensamente adatto ai calcoli in cui è necessario un elevato livello di precisione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top