C# Décimal de type de données de performance
Je suis en train d'écrire une application financière en C# où la performance (vitesse) est critique. Parce que c'est un financière de l'app que j'utilise le type de données Décimal de manière intensive.
J'ai optimisé le code autant que j'ai pu avec l'aide d'un profileur. Avant d'utiliser la Virgule, tout a été fait avec le Double de type de données et la vitesse a été plusieurs fois plus rapide. Toutefois, le Double n'est pas une option en raison de sa nature binaire, causant beaucoup de précision les erreurs au cours de plusieurs opérations.
Est-il décimal de la bibliothèque que je peux l'interface avec le C# qui pourrait me donner une amélioration des performances sur le natif de Décimal de type de données dans .NET?
Sur la base des réponses que j'ai déjà eu, j'ai remarqué que je n'était pas assez clair, alors voici quelques détails supplémentaires:
- L'app doit être aussi rapide comme il peut éventuellement aller (c'est à dire aussi vite qu'il était lors de l'utilisation de la Double à la place de la Virgule serait un rêve). Double était d'environ 15x plus rapide que la Virgule, que les opérations sont basées sur matériel.
- Le matériel est déjà top-notch (je suis en cours d'exécution sur un Double Xénon Quad-Core) et l'application utilise des threads, de sorte que l'utilisation CPU est toujours à 100% sur la machine. En outre, l'application est en cours d'exécution, en 64 bits mode, ce qui lui donne un avantage de performance mesurables sur 32 bits.
- J'ai optimisé au-delà de la santé mentale (plus d'un mois et demi de l'optimisation, ne le croyez ou pas, il faut maintenant env. 1 /5000e, de ce qu'il a fallu faire les mêmes calculs que j'ai utilisé comme référence initialement); cette optimisation impliqués tout: chaîne de traitement, I/O, l'accès base de données et d'index, de mémoire, de boucles, de changer la façon dont certaines choses ont été faites, et même à l'aide de "passer" au dessus de "si" partout où il fait une différence. Le profiler est maintenant montrant clairement que le solde de la performance coupable, c'est sur le type de données Décimal opérateurs. Rien d'autre n'est l'ajout d'une quantité considérable de temps.
- Vous devez me croire ici: je suis allé aussi loin que je pouvais peut-être faire dans le domaine de la C#.NET pour optimiser l'application, et je suis vraiment étonné de ses performances actuelles. Je suis maintenant à la recherche d'une bonne idée pour améliorer la Virgule performance à quelque chose près du Double. Je sais que c'est seulement un rêve, mais je voulais juste vérifier que je pensais de tout ce qui est possible. 🙂
Merci!
- Vous êtes sur le point de l'optimisation prématurée, juste le code de l'application correctement, puis ajuster après le fait
- Vous avez fait tout le faible niveau C# optimisations. Il peut y avoir quelques améliorations algorithmiques gauche (par exemple, en faisant moins d'opérations sur les nombres décimaux).
- Opérations de base de données dans un temps sensible application Financière sonne mal...
Vous devez vous connecter pour publier un commentaire.
vous pouvez utiliser le type de données long. Bien sûr, vous ne serez pas en mesure de stocker des fractions de là, mais si vous le code de votre application pour stocker les pièces de un cent au lieu de livres, et vous serez ok. La précision est de 100% pour les types de données, et sauf si vous travaillez avec un grand nombre (utilisez une version 64 bits de type long) vous serez ok.
Si vous ne pouvez pas le mandat de stocker les pièces de un cent, puis les envelopper d'un entier dans une classe et l'utiliser.
typedef myDecimal long
et ensuite utilisermyDecimal
partout au lieu delong
pour améliorer la lisibilité?Vous dire qu'il doit être rapide, mais ne vous en béton exigences en matière de vitesse? Si non, vous pouvez ainsi optimiser passé le point de la folie 🙂
Comme un ami assis à côté de moi a juste suggéré, vous pouvez mettre à niveau votre matériel à la place? C'est probablement moins cher que de réécrire le code.
Le plus évident option est d'utiliser des entiers au lieu de décimales - où l'on "unité" est quelque chose comme "un millième de un cent" (ou ce que vous voulez - vous voyez l'idée). Si c'est faisable ou pas dépendra des opérations que vous effectuez sur les valeurs décimales pour commencer. Vous devez être très prudent lors de la manipulation, il est facile de faire des erreurs (au moins si vous êtes comme moi).
Ne le générateur de profils montrent notamment les points sensibles de votre application que vous pouvez optimiser individuellement? Par exemple, si vous avez besoin de faire beaucoup de calculs dans une petite zone de code, vous pouvez convertir un nombre décimal en un nombre entier de format, de faire les calculs et ensuite de les convertir en arrière. Qui pourrait empêcher l' API en termes de décimales pour l'essentiel du code, ce qui peut le rendre plus facile à maintenir. Toutefois, si vous n'avez pas prononcé de points d'accès, qui peut ne pas être faisable.
+1 pour le profilage et de nous dire que la vitesse est essentielle, btw 🙂
Le problème est essentiellement que les double/float sont pris en charge dans le matériel, tout en Décimal et le comme ne le sont pas. I. e. vous avez à choisir entre rapidité + précision limitée et une plus grande précision + rendement plus faible.
La question est discutée, mais depuis que je suis à creuser ce problème pendant un temps, je voudrais partager certaines de mes résultats.
La définition du problème: Décimales sont connus pour être beaucoup plus lent que des doubles mais les applications financières ne peuvent tolérer aucun des objets qui surviennent lorsque les calculs sont effectués sur les doubles.
Recherche
Mon objectif était de mesurer les différentes approches de stockage flottant de pointage de chiffres et de faire une conclusion qui doit être utilisé pour notre application.
S'était acceptable pour nous d'utiliser
Int64
pour stocker des nombres à virgule flottante avec une précision fixe. Multiplicateur de 10^6 a été de nous donner à la fois: assez de chiffres pour enregistrer les fractions et stil une grande gamme de stocker de grandes quantités. Bien sûr, vous devez être prudent avec cette approche (la multiplication et de la division des opérations pourrait devenir compliqué), mais nous étions prêts et voulait mesurer cette approche. Une chose que vous devez garder à l'esprit à l'exception des éventuelles erreurs de calcul et les débordements, c'est que généralement on ne peut exposer ces nombres longs à l'API publique. Donc tous les calculs internes pourraient être effectuées à longs mais avant d'envoyer les nombres à l'utilisateur qu'il doit être converti en quelque chose de plus convivial.J'ai implémenté un prototype simple classe qui encapsule une valeur de type long d'une virgule comme la structure (appelé
Money
) et de l'ajouter à l'arpentage.Expérience
J'ai mesuré opérations suivantes: addition, soustraction, multiplication, division, d'égalité et de comparaison relative (plus/moins), de la comparaison. J'ai été en mesure de les opérations sur les types suivants:
double
,long
,decimal
etMoney
. Chaque opération a été réalisée à 1.000.000 de fois. Tous les numéros ont été pré-alloués dans des tableaux, afin de l'appelant code personnalisé dans les constructeurs dedecimal
etMoney
ne devrait pas affecter les résultats.Conclusions
decimal
sont ~15 fois plus lent que les opérations surlong
oudouble
; la division est de ~30 fois plus lent.Decimal
-comme wrapper est meilleure que la performance deDecimal
mais encore bien pire que la performance dedouble
etlong
en raison du manque de soutien de la CLR.Decimal
en chiffres absolus est très rapide: 40.000.000 d'opérations par seconde.Conseils
Decimal
avec votre propre structure en raison de la abcense de soutien de la CLR. Vous pourriez en faire plus vite queDecimal
mais il ne sera jamais aussi rapide quedouble
.Decimal
n'est pas suffisant pour votre application, que vous pourriez envisager de passer vos calculslong
fixe avec précision. Avant de retourner le résultat au client, il doit être converti àDecimal
.Je ne pense pas que les instructions SSE2 peut facile de travailler avec .NET valeurs Décimales. .NET type de données Décimal est 128 bits virgule flottante type http://en.wikipedia.org/wiki/Decimal128_floating-point_format, instructions SSE2 travailler avec 128bit les types integer.
Ce sujet MMX/SSE/SSE2?
je pense que ça va aider...
alors...
virgule est 128 bits type de données et SSE2 est 128bit trop... et il peut ajouter, sous, div, mul décimal de 1 graduation de l'UC...
vous pouvez écrire DLL pour SSE2 à l'aide de VC++ et ensuite utiliser cette DLL dans votre application
e.g
//vous pouvez faire quelque chose comme ceci
VC++
C#
int[]
sera finalement tuer performances lors de la GC de coups de pied dans.Vieille question, encore très valables mais.
Voici quelques chiffres pour appuyer l'idée d'une utilisation prolongée.
Temps pris pour effectuer 100'000'000 ajouts
en un mot, virgule est environ 10 fois plus lent que Long ou Double.
Code:
long
"? Il peut être plus lent, mais vous ne pouvez pas il suffit de comparer les vitesses de, 50 millions ajoute par seconde est juste pas la peine de l'optimisation.long
, n'importe comment beaucoup plus rapidelong
est.Je ne peux pas donner un commentaire ou un vote encore car je viens de commencer sur un débordement de pile. Mon commentaire sur alexsmart (posté le 23 Dec 2008 12:31), c'est que l'expression Round(n/précision, précision), où n est de type int et précisions est long ne fera pas ce qu'il pense:
1) n/précision sera de retour un entier de la division, c'est à dire qu'il sera déjà bien arrondi, mais vous ne serez pas en mesure d'utiliser toutes les décimales. L'arrondissement de comportement est également différente de celle des Mathématiques.Tour(...).
2) Le code "retour de Mathématiques.Round(n/précision, précision).ToString()" ne compile pas en raison d'une ambiguïté entre les Mathématiques.Round(double, int) et des Mathématiques.Ronde(décimal, int). Vous aurez à jeter à la décimale (pas en double, car il est un financière de l'app) et, par conséquent, peut aussi bien aller avec décimale, en premier lieu.
3) n/précision, où la précision est de 4 ne sera pas tronquée à quatre décimales, mais diviser par 4. E. g., Mathématiques.Round( (décimal) (1234567/4), 4) retourne 308641. (1234567/4 = 308641.75), tout ce que vous avez probablement voulu pour se 1235000 (arrondie à une précision de 4 chiffres à partir de la fin 567). Notez que les Mathématiques.Ronde permet d'arrondir à un point fixe, pas une précision fixe.
Mise à jour: je peux ajouter des commentaires maintenant, mais il n'y a pas assez de place pour mettre celui-ci dans la zone de commentaire.
magasin "pennies" en utilisant le double. en dehors de l'analyse de saisie et l'impression des résultats, vous avez la même vitesse que vous avez mesuré. vous surmonter la limite de entier de 64 bits. vous avez une division de ne pas tronquer. remarque : c'est à vous de la façon d'utiliser le double résultat après les divisions. cela me semble être l'approche la plus simple pour vos besoins.