2017-10-09 13 views
2

Mon équipe travaille avec un logiciel financier qui expose les valeurs monétaires sous la forme de doubles flottants C#. À l'occasion, nous devons comparer ces valeurs pour voir si elles sont égales à zéro ou tombent sous une limite particulière. Lorsque j'ai remarqué un comportement inattendu dans cette logique, j'ai rapidement découvert les erreurs d'arrondi inhérentes aux doubles flottants (par exemple 1.1 + 2.2 = 3.3000000000000003). Jusqu'à présent, j'ai principalement utilisé les décimales C# pour représenter les valeurs monétaires.Choix d'une valeur Epsilon pour les comparaisons à virgule flottante

Mon équipe a décidé de résoudre ce problème en utilisant l'approche de la valeur epsilon. Essentiellement, lorsque vous comparez deux nombres, si la différence entre ces deux nombres est inférieure à epsilon, ils sont considérés égaux. Nous avons mis en œuvre cette approche de la même manière que décrit dans l'article ci-dessous: https://www.codeproject.com/Articles/383871/Demystify-Csharp-floating-point-equality-and-relat

Notre défi a été de déterminer une valeur appropriée pour epsilon. Nos valeurs monétaires peuvent avoir jusqu'à 3 chiffres à droite de la virgule décimale (échelle = 3). Cela signifie que le plus grand epsilon que nous pourrions utiliser est .0001 (quelque chose de plus grand et le troisième chiffre est ignoré). Puisque les valeurs d'epsilon sont supposées être petites, nous avons décidé de le déplacer d'un point décimal vers .00001 (juste pour être sûr, pourrait-on dire). Les doubles C# ont une précision de at least 15 digits, donc je crois que cette valeur d'epsilon devrait fonctionner si le nombre à gauche du point décimal est inférieur ou égal à 10 chiffres (15 - 5 = 10, où 5 est le nombre de chiffres epsilon est à droite de la virgule décimale). Avec 10 chiffres, nous pouvons représenter des valeurs dans les milliards, jusqu'à 9999999999999. Il est possible que nous ayons des centaines de millions, mais nous ne nous attendons pas à des milliards, donc cette limite devrait suffire.

Est-ce que ma justification pour choisir cette valeur d'epsilon est correcte? J'ai trouvé beaucoup de ressources qui discutent de cette approche, mais je n'ai pas trouvé beaucoup de ressources qui fournissent des conseils sur le choix d'epsilon.

+2

Je pensais que l'utilisation normale, même DP, IEEE754 n'était pas une bonne idée pour les calculs financiers. La sagesse perçue est d'utiliser le type [décimal] de C# (https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/decimal); avez-vous considéré cela? –

+0

@IsaacWoods J'écris un code d'extension pour un logiciel financier sur étagère, donc je n'ai aucun contrôle sur les types de données qu'il utilise. J'ai pensé à convertir les valeurs doubles en décimales, mais si le double contient déjà une erreur d'arrondi, il est simplement copié dans la décimale. –

+1

En raison de certaines expériences douloureuses, en commençant par un gestionnaire me disant "Vous n'aurez plus jamais à lire plus de 200 cartes perforées.", les clauses du formulaire" nous ne nous attendons pas à des milliards "me rendent très nerveux Comment allez-vous imposer la limite? Que se passe-t-il s'il y a une période d'inflation? Vous obtenez une méga banque en tant que client Votre code est utilisé avec une devise différente? –

Répondre

2

Votre raisonnement semble solide, mais comme vous l'avez déjà découvert, c'est un problème compliqué. Vous voudrez peut-être lire What Every Computer Scientist Should Know About Floating-Point Arithmetic. Vous avez un minimum de 15 chiffres de précision en utilisant 64 bits doubles. Cependant, vous voudrez aussi valider vos entrées car les flotteurs peuvent contenir Nan, +/- Infinity, zéro négatif et une "plage" considérablement plus grande que 15 chiffres décimaux. Si quelqu'un donne à votre bibliothèque une valeur comme 1.2E102, devriez-vous la traiter ou la considérer hors de portée? Idem avec de très petites valeurs. Garbage In, Garbage out, mais ça pourrait être sympa si vous codez détecté "l'odeur" de la poubelle et au moins l'avez connecté.

Vous pouvez également envisager de fournir une propriété pour la précision de réglage ainsi que différentes formes d'arrondi. Cela dépend en grande partie des spécifications avec lesquelles vous travaillez. Vous pourriez également vouloir déterminer si ces valeurs peuvent représenter des devises autres que les dollars (1 dollar est actuellement> 112 yens). Long et le short de celui-ci en choisissant votre epsilon un chiffre en dessous de vos besoins (donc quatre chiffres à droite de la décimale) est bon et vous donne un chiffre à utiliser pour arrondir cohérente. Sinon $ 10.0129 et $ 10.0121 seraient égaux mais leur somme serait de $ 20.025 au lieu de $ 20.024 ... les comptables aiment les choses qui "marchent".