Question

Je peux nommer trois avantages à utiliser double (ou float ) au lieu de décimal :

  1. Utilise moins de mémoire.
  2. Plus rapide car les opérations mathématiques en virgule flottante sont nativement prises en charge par les processeurs.
  3. Peut représenter un plus grand nombre de nombres.

Mais ces avantages semblent s’appliquer uniquement aux opérations nécessitant beaucoup de calcul, telles que celles trouvées dans les logiciels de modélisation. Bien entendu, les doublons ne doivent pas être utilisés lorsqu'une précision est requise, telle que des calculs financiers. Existe-t-il des raisons pratiques de choisir double (ou float ) au lieu de décimal dans " normal " applications?

Édité pour ajouter: Merci pour toutes les bonnes réponses que j’ai apprises.

Une autre question: quelques personnes ont fait valoir que les doubles peuvent représenter plus précisément des nombres réels. Une fois déclarés, je penserais qu’ils les représentent généralement avec plus de précision. Mais est-ce une affirmation vraie que la précision peut diminuer (parfois considérablement) lorsque des opérations en virgule flottante sont effectuées?

Était-ce utile?

La solution

Je pense que vous avez très bien résumé les avantages. Vous manquez cependant un point. Le type décimal n'est que davantage exactes pour représenter les bases 10 (par exemple, celles utilisées dans les calculs monétaires / financiers). En général, le type double va offrir au moins la même précision (quelqu'un me corrige si je me trompe) et certainement une vitesse supérieure pour les nombres réels arbitraires. La conclusion est simple: utilisez toujours double si vous avez besoin de la précision base 10 proposée par décimal .

Modifier:

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

  1. le fait que certains nombres (le plus évidemment des nombres décimaux) ne peuvent pas être vraiment représentés sous forme de virgule flottante
  2. des erreurs d'arrondi se produisent, comme si vous effectuiez le calcul à la main. Cela dépend beaucoup du contexte (combien d'opérations que vous effectuez) si ces erreurs sont suffisamment significatives pour mériter une longue réflexion.

Dans tous les cas, si vous souhaitez comparer deux nombres à virgule flottante qui devraient théoriquement être équivalents (mais ont été calculés à l'aide de calculs différents), vous devez autoriser un certain degré de tolérance (ce qui varie mais qui est typiquement très petit).

Pour un aperçu plus détaillé des cas particuliers dans lesquels des erreurs de précision peuvent être introduites, voir la section Accuracy du article de Wikipedia . Enfin, si vous souhaitez une discussion sérieuse en profondeur (et mathématique) des nombres / opérations en virgule flottante au niveau de la machine, essayez de lire l'article souvent cité Ce que tout informaticien devrait savoir sur l'arithmétique en virgule flottante .

Autres conseils

Vous semblez bénéficier des avantages de l’utilisation d’un type à virgule flottante. J'ai tendance à concevoir des décimales dans tous les cas, et je me fie à un profileur pour me faire savoir si les opérations sur la décimale sont à l'origine de goulots d'étranglement ou de ralentissements. Dans ces cas, je vais "décoller". doubler ou flotter, mais uniquement en interne, et essayer avec précaution de gérer la perte de précision en limitant le nombre de chiffres significatifs de l'opération mathématique en cours d'exécution.

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 véritable problème des types à virgule flottante concerne 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 en fonction de 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 nombres décimaux C # :

  

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

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

  

J'ai tendance à concevoir des décimales en tout   cas, et comptent sur un profileur pour laisser   moi savoir si les opérations sur le nombre décimal est   provoquant des goulots d'étranglement ou des ralentissements.

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

Le nombre décimal n’est pas infiniment précis (il est impossible de représenter la précision infinie pour les données non intégrales dans un type de données primitif), mais il est bien plus précis que double:

  • decimal = 28-29 chiffres significatifs
  • double = 15-16 chiffres significatifs
  • float = 7 chiffres significatifs

EDIT 2

En réponse au commentaire de Konrad Rudolph , l'élément n ° 1 (ci-dessus) est tout à fait correct. L'agrégation de l'imprécision est en effet composée. 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(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();
}

Ceci 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 nous arrondissions probablement correctement), et le flottant est beaucoup moins précis au point où il a été réduit à seulement deux chiffres significatifs.

Utilisez un nombre décimal pour les valeurs de base 10, par ex. calculs financiers, comme d'autres l'ont suggéré.

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

Par exemple, si vous souhaitez calculer le poids de chaque ligne d'un portefeuille, utilisez double car le résultat totalise presque 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;

Encore une fois, prenons 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 / somme (valeur marchande)) est généralement mieux représenté sous forme de double.

Utilisez un double ou un float lorsque vous n’avez pas besoin de précision. Par exemple, dans un jeu de plateforme que j’ai écrit, j’utilisais un float pour stocker les vélocités du joueur. Évidemment, je n’ai pas besoin de super précision ici parce que j’ai finalement arrondi à un Int pour dessiner à l’écran.

Dans certaines méthodes comptables, envisagez la possibilité d'utiliser des types intégraux à la place ou conjointement. Par exemple, supposons que les règles que vous appliquez exigent que chaque résultat de calcul soit reporté d’au moins 6 décimales et que le résultat final soit arrondi au cent le plus proche.

Un calcul de 1/6 de 100 $ donne 16,666666666666666 ..., de sorte que la valeur reportée dans une feuille de calcul sera de 16,666667 $. Les doubles et les décimales doivent 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 nombre entier 16666667. Chaque calcul suivant peut être effectué avec la même précision et reporté de la même manière. En reprenant l’exemple, je calcule la taxe de vente du Texas sur ce montant (16666667 * .0825 = 1375000). En ajoutant les deux (c’est une courte feuille de calcul) 1666667 + 1375000 = 18041667. Le déplacement de la virgule décimale nous donne 18,041667, soit 18,04 USD.

Bien que ce court exemple ne produise pas d'erreur cumulative utilisant la double ou la décimale, il est assez facile de montrer les cas où le simple calcul de la double ou de la décimale et le report entraîneraient une erreur significative. Si les règles que vous appliquez exigent un nombre limité de décimales, stockez chaque valeur sous forme d’entier en multipliant par 10 ^ (nombre requis de décimales), puis divisée par 10 ^ (nombre requis de décimales) pour obtenir le nombre réel. la valeur évitera toute erreur cumulative.

Dans les cas où il n’ya pas de fractions de penny (par exemple, un distributeur automatique), il n’ya aucune raison d’utiliser des types non intégraux. Pensez-y simplement en comptant des sous, pas en dollars. J'ai vu du code où chaque calcul ne comportait que des sous, mais l'utilisation de doubles entraînait des erreurs! Integer only math a supprimé le problème. Donc, ma réponse non conventionnelle est, dans la mesure du possible, d’abandonner le double et le décimal.

Si vous avez besoin d'interopérabilité binaire avec d'autres langages ou plates-formes, vous devrez peut-être utiliser float ou double, qui sont standardisées.

Remarque: cet article est basé sur les informations relatives aux capacités du type décimal fournies par http: // csharpindepth. com / Articles / General / Decimal.aspx et ma propre interprétation de ce que cela signifie. Je supposerai que Double correspond à la double précision IEEE normale.

Note2: le plus petit et le plus grand dans cet article indiquent la magnitude 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 ne peut pas. C’est important dans les grands livres financiers et similaire, où il est important que les résultats correspondent exactement à ce que donnerait un calcul humain.
  • " décimal " a une mantisse beaucoup plus grande que celle de "double". Cela signifie que, pour les valeurs comprises dans cet intervalle normalisé, "décimal". aura une précision beaucoup plus élevée que le double.

Contre décimal

  • Cela sera beaucoup plus lent (je n'ai pas de points de repère, mais je suppose qu'au moins un ordre de grandeur est peut-être supérieur), la décimale ne bénéficiera d'aucune accélération matérielle et l'arithmétique nécessitera une multiplication / division par pouvoirs relativement coûteuse. de 10 (ce qui est beaucoup plus coûteux que la multiplication et la division par des puissances de 2) pour faire correspondre l'exposant avant addition / soustraction et ramener l'exposant dans la plage après multiplication / division.
  • le nombre décimal débordera plus tôt que le double. les nombres décimaux ne peuvent représenter que des nombres allant jusqu'à ± 2 96 -1. Par comparaison, double peut représenter des nombres allant jusqu'à presque ± 2 1024
  • le nombre décimal dépassera plus tôt. Les plus petits nombres pouvant être représentés en décimal sont ± 10 -28 . Par comparaison, double peut représenter des valeurs inférieures à 2 -149 (environ 10 -45 ) si les nombres subnromaux sont pris en charge et 2 -126 (environ 10 -38 ) s'ils ne le sont pas.
  • décimal occupe deux fois plus de mémoire que double.

Mon avis est que vous devriez utiliser par défaut " décimal " pour travailler avec d’argent et dans d’autres cas où il est important d’apparaître avec exactitude dans le calcul humain et que vous devez utiliser double comme choix par défaut le reste du temps.

Utilisez des points flottants si vous accordez de la valeur à la performance.

Choisissez le type en fonction de votre application. Si vous avez besoin de précision, comme dans l'analyse financière, vous avez répondu à votre question. Mais si votre demande peut être réglée avec une estimation, votre ok avec double.

Votre application nécessite-t-elle un calcul rapide ou aura-t-il tout le temps du 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, météore frappant une précision de la planète? Ceux qui auraient besoin d'un peu de précision:)

Le nombre décimal a des octets plus larges, double est pris en charge en natif par le processeur. La décimale étant en base 10, une conversion décimale-à-double est effectuée alors qu'une décimale est calculée.

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

N'oubliez pas que .NET CLR ne prend en charge 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 double valeur sera sérialisée en notation scientifique par défaut 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 un facteur important.

Cela dépend de vos besoins.

Parce que float et double sont des types de données binaires, vous avez certains diifculties et erreurs dans la façon dont les nombres sont arrondis. Ainsi, par exemple double arrondirait 0.1 à 0.100000001490116, doublerait également arrondir 1/3 à 0,33333334326441. En termes simples, tous les nombres réels n’ont pas une représentation précise dans les types doubles

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 binaire. Ainsi, l'arithmétique décimale à virgule flottante ne perd pas en précision lors du stockage et du traitement des nombres en virgule flottante. Cela le rend parfaitement adapté aux calculs nécessitant un niveau élevé de précision.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top