Quand devrais-je utiliser double au lieu de décimal?

Je peux nommer trois avantages à utiliser le double (ou le float ) au lieu du decimal :

  1. Utilise moins de mémoire.
  2. Plus rapide car les opérations mathématiques en virgule flottante sont supscopes en natif par les processeurs.
  3. Peut représenter une plus grande gamme de nombres.

Mais ces avantages semblent s’appliquer uniquement aux opérations de calcul intensif, telles que celles que l’on trouve dans les logiciels de modélisation. Bien sûr, les doubles ne doivent pas être utilisés lorsque la précision est requirejse, comme les calculs financiers. Existe-t-il des raisons pratiques de choisir le double (ou le float ) plutôt que le decimal dans les applications “normales”?

Edité pour append: Merci pour toutes les bonnes réponses, j’ai appris d’eux.

Une autre question: quelques personnes ont fait valoir que les doubles pouvaient représenter plus précisément des nombres réels. Lorsqu’ils sont déclarés, je pense qu’ils les représentent généralement plus précisément. Mais est-il vrai que la précision peut diminuer (parfois de manière significative) lorsque des opérations en virgule flottante sont effectuées?

Je pense que vous avez bien résumé les avantages. Vous manquez cependant un point. Le type decimal est seulement plus précis pour représenter les nombres de base 10 (par exemple, ceux utilisés dans les calculs de devise / financiers). En général, le double type offrira au moins autant de précision (quelqu’un me corrige si je me trompe) et une vitesse nettement supérieure pour des nombres réels arbitraires. La conclusion simple est la suivante: lorsque vous envisagez d’utiliser, utilisez toujours le double sauf si vous avez besoin de la précision de base 10 offerte par la decimal .

Modifier:

En ce qui concerne votre question supplémentaire concernant la diminution de la précision des nombres à virgule flottante après les opérations, il s’agit d’une question légèrement plus subtile. En effet, la précision (j’utilise le terme de manière interchangeable pour la précision ici) diminuera progressivement après chaque opération. Cela est dû à deux raisons:

  1. le fait que certains nombres (le plus souvent des décimales) ne peuvent pas être réellement représentés sous forme de virgule flottante
  2. des erreurs d’arrondi se produisent, comme si vous faisiez le calcul à la main. Cela dépend beaucoup du contexte (nombre d’opérations que vous effectuez), que ces erreurs soient suffisamment importantes pour justifier une reflection approfondie.

Dans tous les cas, si vous voulez comparer deux nombres à virgule flottante qui devraient en théorie être équivalents (mais qui ont été calculés différemment), vous devez autoriser un certain degré de tolérance (combien varie, mais est généralement très petit) .

Pour un aperçu plus détaillé des cas particuliers où des erreurs de précision peuvent être introduites, voir la section Précision de l’article de Wikipedia . Enfin, si vous voulez une discussion sérieuse (et mathématique) sur les opérations et les nombres à virgule flottante au niveau de la machine, lisez l’article souvent cité Ce que chaque informaticien devrait savoir sur l’arithmétique en virgule flottante.

Vous semblez aller de l’avant avec les avantages d’utiliser un type à virgule flottante. J’ai tendance à concevoir des décimales dans tous les cas et à faire appel à un profileur pour me faire savoir si les opérations en décimal provoquent des goulots d’étranglement ou des ralentissements. Dans ces cas-là, je vais “lancer” pour doubler ou flotter, mais le faire uniquement en interne, et essayer de gérer avec soin la perte de précision en limitant le nombre de chiffres significatifs dans l’opération mathématique effectuée.

En général, si votre valeur est transitoire (non réutilisée), vous pouvez utiliser un type à virgule flottante en toute sécurité. Le vrai problème avec les types à virgule flottante est les trois scénarios suivants.

  1. Vous agrégez des valeurs à virgule flottante (auquel cas les erreurs de précision sont composées)
  2. Vous construisez des valeurs basées sur la valeur à virgule flottante (par exemple dans un algorithme récursif)
  3. Vous faites des calculs avec un très grand nombre de chiffres significatifs (par exemple, 123456789.1 * .000000000000000987654321 )

MODIFIER

Selon la documentation de référence sur les décimales C # :

Le mot-clé décimal indique un type de données 128 bits. Par rapport aux types à virgule flottante, le type décimal a une plus grande précision et une plus petite gamme, ce qui le rend approprié pour les calculs financiers et monétaires.

Donc, pour clarifier ma déclaration ci-dessus:

J’ai tendance à concevoir des décimales dans tous les cas et à faire appel à un profileur pour me faire savoir si les opérations en décimal provoquent des goulots d’étranglement ou des ralentissements.

Je n’ai travaillé que dans des secteurs où les décimales sont favorables. Si vous travaillez sur des moteurs graphiques ou graphiques physiques, il est probablement beaucoup plus avantageux de concevoir un type à virgule flottante (float ou double).

Decimal n’est pas infiniment précis (il est impossible de représenter une précision infinie pour la non-intégrale dans un type de données primitif), mais il est beaucoup plus précis que le double:

  • décimal = 28-29 chiffres significatifs
  • double = 15-16 chiffres significatifs
  • float = 7 chiffres significatifs

EDIT 2

En réponse au commentaire de Konrad Rudolph , l’article n ° 1 (ci-dessus) est certainement correct. L’agrégation de l’imprécision est en effet un composé. Voir le code ci-dessous pour un exemple:

 private const float THREE_FIFTHS = 3f / 5f; private const int ONE_MILLION = 1000000; public static void Main(ssortingng[] args) { Console.WriteLine("Three Fifths: {0}", THREE_FIFTHS.ToSsortingng("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(); } 

Cela génère les éléments suivants:

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

Comme vous pouvez le constater, même si nous ajoutons à partir de la même source constante, les résultats du double sont moins précis (bien que probablement arrondis correctement), et le flottant est beaucoup moins précis, à tel point qu'il a été réduit à seulement deux chiffres significatifs.

Utilisez les décimales pour les valeurs de base 10, par exemple les calculs financiers, comme d’autres l’ont suggéré.

Mais le double est généralement plus précis pour les valeurs calculées arbitraires.

Par exemple, si vous souhaitez calculer le poids de chaque ligne d’un portefeuille, utilisez le double car le résultat sera presque égal à 100%.

Dans l’exemple suivant, doubleResult est plus proche de 1 que 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; 

Donc, prenant à nouveau l’exemple d’un portefeuille:

  • La valeur de marché de chaque ligne du portefeuille est une valeur monétaire et serait probablement mieux représentée sous forme décimale.

  • Le poids de chaque ligne du portefeuille (= valeur marchande / SUM (valeur marchande)) est généralement mieux représenté par le double.

Utilisez un double ou un flottant lorsque vous n’avez pas besoin de précision. Par exemple, dans un jeu de plateforme que j’ai écrit, j’ai utilisé un flotteur pour stocker les vitesses du lecteur. Evidemment, je n’ai pas besoin de super précision ici car je finis par arriver à un Int pour dessiner à l’écran.

Dans certains Comptabilité, envisagez la possibilité d’utiliser des types intégraux à la place ou en conjonction. Par exemple, disons que les règles que vous utilisez sous exigent que chaque résultat de calcul soit reporté à au moins 6 décimales et que le résultat final soit arrondi au centime le plus proche.

Un calcul de 1/6 de 100 $ rapporte 16.66666666666666 …, donc la valeur rescope dans une feuille de calcul sera 16.666667 $. Le double et le décimal devraient donner ce résultat avec précision à 6 décimales. Cependant, nous pouvons éviter toute erreur cumulative en reportant le résultat sous la forme d’un entier 16666667. Chaque calcul ultérieur peut être effectué avec la même précision et être reporté de la même manière. En reprenant l’exemple, je calcule la taxe de vente Texas sur ce montant (16666667 * .0825 = 1375000). En ajoutant les deux (c’est une feuille de travail courte) 1666667 + 1375000 = 18041667. Remettre le point décimal nous donne 18.041667, soit 18.04 $.

Bien que ce court exemple ne produise pas une erreur cumulative en utilisant le double ou le décimal, il est assez facile de montrer les cas où le simple calcul du double ou du décimal et le report de l’erreur accumulerait une erreur significative. Si les règles que vous utilisez nécessitent un nombre limité de décimales, en stockant chaque valeur sous la forme d’un nombre entier en multipliant par 10 ^ (nombre de décimales requirejs), puis en divisant par 10 ^ (nombre de décimales requirejs) pour obtenir le nombre réel valeur évitera toute erreur cumulative.

Dans les situations où il n’ya pas de fractions de sous (par exemple, un dissortingbuteur automatique), il n’ya aucune raison d’utiliser des types non intégraux. Il suffit de penser à compter des sous, pas des dollars. J’ai vu du code où chaque calcul n’impliquait que des centimes, mais l’utilisation du double entraînait des erreurs! Entier seul maths enlevé le problème. Donc, ma réponse non conventionnelle est, si possible, de renoncer à la fois au double et au décimal.

Si vous avez besoin d’interpolation binary avec d’autres langages ou plates-formes, vous devrez peut-être utiliser float ou double, qui sont standardisés.

Note: cet article est basé sur des informations sur les capacités du type décimal à partir de http://csharpindepth.com/Articles/General/Decimal.aspx et sur ma propre interprétation de ce que cela signifie. Je suppose que Double est une double précision IEEE normale.

Note2: la plus petite et la plus grande dans cet article se rapportent à l’ampleur du nombre.

Avantages de “décimal”.

  • “décimal” peut représenter exactement des nombres qui peuvent être écrits sous forme de fractions décimales (suffisamment courtes), double impossible. Ceci est important dans les grands livres financiers et similaires, où il est important que les résultats correspondent exactement à ce que les calculs d’un humain pourraient faire.
  • “decimal” a une mantisse beaucoup plus grande que “double”. Cela signifie que pour les valeurs comsockets dans sa plage normalisée, la décimale aura une précision beaucoup plus élevée que le double.

Contre de décimal

  • Ce sera beaucoup plus lent (je n’ai pas de benchmarks mais je devine au moins un ordre de grandeur peut-être plus), le décimal ne bénéficiera d’aucune accélération matérielle et arithmétique nécessitant une multiplication / division relativement coûteuse de 10 ( ce qui est beaucoup plus cher que la multiplication et la division par puissances de 2) pour faire correspondre l’exposant avant addition / soustraction et ramener l’exposant dans la plage après multiplication / division.
  • décimale débordera plus tôt que la double volonté. décimal ne peut représenter que des nombres allant jusqu’à ± 2 96 -1. Par comparaison, le double peut représenter des nombres jusqu’à près de ± 2 1024
  • décimale sera sous-développée plus tôt. Les plus petits nombres représentables en décimal sont ± 10 -28 . Par comparaison, le double peut représenter des valeurs allant de 2 à 149 (environ 10 à 45 ) si les nombres subnromaux sont pris en charge et de 2 à 126 (environ 10 à 38 ) s’ils ne le sont pas.
  • le nombre décimal prend deux fois plus de mémoire que le double.

Mon opinion est que vous devriez utiliser par défaut “décimal” pour le travail d’argent et d’autres cas où la correspondance exacte du calcul humain est importante et que vous devez utiliser double comme choix par défaut le rest du temps.

Utilisez des points flottants si vous appréciez la performance au désortingment de l’exactitude.

Choisissez le type en fonction de votre application. Si vous avez besoin de précision comme dans l’parsing financière, vous avez répondu à votre question. Mais si votre application peut régler avec une estimation votre ok avec double.

Votre application nécessite-t-elle un calcul rapide ou aura-t-il tout le temps au monde pour vous donner une réponse? Cela dépend vraiment du type d’application.

Graphic faim? float ou double suffit. Analyse de données financières, meteors frappant une planète de type précision? Ceux-ci auraient besoin d’un peu de précision 🙂

Decimal a des octets plus larges, le double est supporté nativement par le CPU. Decimal est la base-10, donc une conversion décimal-à-double se produit pendant qu’un nombre décimal est calculé.

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

Gardez à l’esprit que .NET CLR ne supporte que Math.Pow (double, double). La décimale n’est pas prise en charge.

.NET Framework 4

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

Une valeur double sera sérialisée par défaut à la notation scientifique si cette notation est plus courte que l’affichage décimal. (par exemple, .00000003 sera 3e-8) Les valeurs décimales ne seront jamais sérialisées en notation scientifique. Lors de la sérialisation pour la consommation par une partie externe, cela peut être une considération.

Cela dépend de ce dont vous en avez besoin.

Étant donné que float et double sont des types de données binarys, vous avez des difficultés et des erreurs dans les nombres de tours, par exemple le double arrondirait 0.1 à 0.100000001490116, le double arrondirait également 1/3 à 0.33333334326441. Simplement mettre tous les nombres réels ont une représentation précise en double type

Heureusement, C # prend également en charge l’arithmétique décimale à virgule flottante, où les nombres sont représentés via le système numérique décimal plutôt que le système binary. Ainsi, l’arithmétique en virgule flottante décimale ne perd pas de sa précision lors du stockage et du traitement des nombres à virgule flottante. Cela le rend extrêmement adapté aux calculs nécessitant un niveau de précision élevé.