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, "eseguirò il down cast" per raddoppiare o fluttuare, ma lo farò solo internamente e cercherò attentamente di 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 a virgola mobile sono i seguenti tre scenari.
- Stai aggregando valori in virgola mobile (nel qual caso gli errori di precisione sono composti)
- Si creano valori in base al valore in virgola mobile (ad esempio in un algoritmo ricorsivo)
- Stai facendo matematica con un numero molto ampio di cifre significative (ad esempio
123456789.1 * .000000000000000987654321
)
MODIFICARE
Secondo la documentazione di riferimento sui decimali C # :
La parola chiave decimale indica un tipo di dati a 128 bit. Rispetto ai tipi a virgola mobile, il tipo decimale ha una maggiore precisione e un intervallo più piccolo, che lo rende adatto per calcoli finanziari e monetari.
Quindi, per chiarire la mia affermazione di cui sopra:
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.
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 un 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 n. 1 (sopra) è decisamente corretto. L'aggregazione delle imprecisioni in effetti si aggrava. Vedi il codice qui 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();
}
Ciò 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.