Currency : un type méconnu (money sous sql-server)

Soyez le premier à donner votre avis sur cette source.

Snippet vu 11 398 fois - Téléchargée 43 fois

Contenu du snippet


La plupart des programmeurs utilisent le type Double pour manipuler des données monétaires. Pourtant il y a un type spécialement adapté pour gérer les montants : il s'agit du type Currency (Money Sous SQL-Server).
Vous pensez pouvoir vous contenter du type Double, vous avez probablement tors....


Voici un test qui va vous faire comprendre en deux secondes le problème des montants.
Sous Visual Basic, ouvrez la fenêtre de déboguage et tapez :
? 100.99 - 50.45 - 50.54
VB vous répond :
-7,105427357601E-15

Que s'est-il passé ?
Non, votre processeur n'a pas fait d'erreur de calcul. VB ne s'ait pas trompé.
Un code équivalent en C++ donnerait le même comportement.
En fait, sans vous le dire, VB a utilisé le type Single ou Double pour vos montants.
Ces deux type sont des représentation 'à virgule' flottante d'un nombre réel.
C'est donc une approximation du nombre qui est enregistré.

Comme le montre le résultat du test, l'approximation est très bonne (à 15 décimales près),
mais engendre une erreur dès qu'on veut comparer ce montant à un autre.

Par exemple, faites le test :
? (100.99 - 50.45 - 50.54) = 0
retourne
Faux

Et là, y'a problème.
Sans le savoir, votre application intègre peut être cette erreur !!

Heureusement, les concepteurs de langage sont conscients de ce problème.
Ils vous ont donc préparé un type spécial : le type Currency.
Ce type n'est pas une représentation 'à virgule flottante' mais une représentation 'à virgule fixe' avec 4 décimales après la virgule.
Il est spécialement adapté aux données monétaires car toutes les monnaies du monde ne gèrent pas plus de 2 décimales dans les montants. Donc avec une précision de 4, on est largement bon. En plus, comme sa représentation est fixe, les calculs de grandes sommes est particulièrement rapide.

Dans vos bases de données :
Il existe souvent un type numérique fixe pour les champs dans les bases de données.
Mais il y a toujours aussi un type spécial pour les montants (Money sous SQL-Server). Il est plus adapté.

Voilà, en conclusion je vous conseille d'utiliser systématiquement Currency (VB) ou Money (SQL-Server) pour travailler sur des montants.

Source / Exemple :


.

A voir également

Ajouter un commentaire

Commentaires

PtitJeoJeo
Messages postés
85
Date d'inscription
mardi 29 janvier 2002
Statut
Membre
Dernière intervention
18 avril 2005
-
je retien !
Ptitjeojeo
cs_OphidiaN
Messages postés
235
Date d'inscription
mercredi 4 avril 2001
Statut
Membre
Dernière intervention
9 novembre 2007
-
kler, j'avais jamais vu....
Sirocooo
Messages postés
412
Date d'inscription
mercredi 19 décembre 2001
Statut
Membre
Dernière intervention
7 avril 2008
1 -
Par expérience je peux dire aujourdh'ui que stocker ses données avec virgule flotante ou fixe source de bugs et d'erreurs.
Quand on développe une grosse appli, un jour ou l'autre ca pete à la figure !!!

Je conseil de travailer en entier long (donc en centimes) c'est beaucoup plus fiable et précis.
à bon entendeur,...
skrol29
Messages postés
115
Date d'inscription
vendredi 3 mai 2002
Statut
Membre
Dernière intervention
17 novembre 2014
-
>Je conseil de travailer en entier long (donc en centimes)

C'est justement comme cela que fonctionne le type Currency.
Il stock le montant sans la virgule, et le gère comme un entier pour les opérations linéaires (somme, multiplication). Mais il restitue la représentation interne divisées 1000 (4 décimales) pour l'affichage et les autres calculs.
Trop fort le Currency.
cs_gogomanu
Messages postés
29
Date d'inscription
mardi 7 janvier 2003
Statut
Membre
Dernière intervention
26 mars 2009
-
Excellent currency, en regardant dans les docs j'avais pas bien compris à quoi ça servait j'avais l'impression que c'était une sorte de "double" en fait.
Très bon à savoir, je me suis flingué la tête à faire une procédure d'arrondi, ça parait tout con mais j'ai dû la retoucher plusieurs fois!

Public Function Arrondi(Calc As Variant, Optional ByVal ArrondiNombres% 2, Optional ByVal JusteTronquer As Boolean False) As Double
' Arrondi à N chiffres après la virgule (0,003 -> 0,00 0,005 -> 0,01)
' Calc: Nombre à arrondir
' ArrondiNombres: Nombre de chiffres après la virgule
' JusteTronquer: Arrondir en dessous
'
' Optimisation avec un select case pour essayer d'améliorer ce qui est
' facilement améliorable: arrondi 2 est très fréquent par exemple.
'
Dim Decal As Double, Decal2 As Double, Tmp As Double

On Error GoTo Err
Select Case ArrondiNombres
Case 2:
Decal = 100
Decal2 = 0.005
Case 0:
Decal = 1
Decal2 = 0.5
Case 1:
Decal = 10
Decal2 = 0.05
Case 3:
Decal = 1000
Decal2 = 0.0005
Case Else:
Decal = 10 ^ ArrondiNombres
Decal2 = (1 / (Decal + Decal))
End Select
If JusteTronquer Then Decal2 = 0

Tmp = Nz(Calc, 0)
If Decal2 <> 0 Then Tmp = Tmp + Decal2 ' pour ne pas déformer le "Double"
If Decal <> 1 Then Tmp = Tmp * Decal
'*** Je veux garder la partie ENTIERE EXACTE (merci access de daube)
Tmp = Int(Tmp)
If Decal <> 1 Then Tmp = Tmp / Decal
Arrondi = Tmp
'*** La première version paraissait simple: mais bug dans certains cas !!! :
' Arrondi = Int((Nz(Calc, 0) + Decal2) * Decal) / Decal
'********** fin de la première version
Fin:
Exit Function

Err:
MsgBox "Erreur Arrondi: " & vbCr & Err.Number & ": " & Err.Description, vbExclamation
Resume Fin

End Function

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.