PC SOFT

FORUMS PROFESSIONNELS
WINDEVWEBDEV et WINDEV Mobile

Accueil → WINDEV 2025 → arrondi monétaire VS arrondi numérique (je ne comprends plus rien)
arrondi monétaire VS arrondi numérique (je ne comprends plus rien)
Débuté par AlexisPERR, 20 mai 2025 14:56 - 7 réponses
Membre enregistré
133 messages
Posté le 20 mai 2025 - 14:56
Bon je pensais avoir tout compris sur les arrondis, mais WinDEV arrive encore à me surprendre.

Examinons l'égalité mathématiquement exacte 1,583333 * 0,9 = 1,4249997

Le résultat 1,4249997 ayant 7 décimales; il ne tiendra pas dans un numérique ou monétaire, qui sont limités à 6 par défaut.

Que ce passe-t-il si l'on stocke cette valeur dans une variable ?

Faisons le test ensemble.

monNumérique1 is numeric = 1,4249997
monMonétaire1 is currency = 1,4249997

Trace(monNumérique1) donne 1,424999
Trace(monMonétaire1) donne 1,425


Ca alors, une première différence inattendue. Mais peut-être est-ce du au nombres entré tel quel, traité par le compilateur comme des réels. Forçont le type en mettant 0m ou 0n devant.

monNumérique2 is numeric = 0m1.4249997
monMonétaire2 is currency = 0m1.4249997

Trace(monNumérique2) donne 1,424999
Trace(monMonétaire2) donne 1,424999

monNumérique3 is numeric = 0n1.4249997
monMonétaire3 is currency = 0n1.4249997

Trace(monNumérique3) donne 1,424999
Trace(monMonétaire3) donne 1,424999


Ah, là cela donne bien la même chose. On voit que le nombre a été tronqué à 6 chiffres, le 0,0000007 est perdu.
Si la règle usuelle d'arrondi avait été suivie, alors cela aurait du donner 1,425000 (de 5 à 9 on arrondi au chiffre supérieur).


Mais maintenant que se passe-t-il si l'on écrit 1,583333 * 0,9 au lieu de 1,4249997 ? Certainement cela ne doit rien changer ?


monNumérique4 is numeric = 0n1.583333 * 0n0.9
monMonétaire4 is currency = 0n1.583333 * 0n0.9

Trace(monNumérique4) donne 1,424999
Trace(monMonétaire4) donne 1,424999

monNumérique5 is numeric = 0m1.583333 * 0m0.9
monMonétaire5 is currency = 0m1.583333 * 0m0.9

Trace(monNumérique5) donne 1,425
Trace(monMonétaire5) donne 1,425


Patatra. Le calcul fait sur des scalaires numériques est différent sur les scalaires monétaires !

En d'autres termes,

// on a
0m1.583333 * 0m0.9 = 1,425
// alors que
0n1.583333 * 0n0.9 = 1,424999
// et
0m1.4249997 = 1,424999
0n1.4249997 = 1,424999


Je ne pense pas que cela soit normal, qu'en pensez-vous ?
Membre enregistré
1 009 messages
Posté le 20 mai 2025 - 15:22
Membre enregistré
133 messages
Posté le 20 mai 2025 - 17:33
> Non essayé, mais le souci n'est-il pas dû au trace :

intéressant, mais non.
Membre enregistré
133 messages
Posté le 22 mai 2025 - 11:55
pour être un peu plus clair, les numériques ne se comportent pas comme les monétaires
(le numérique tronque, alors que le monétaire arrondi)

La preuve avec ce code, on fait le même calcul avec 3 variables numériques, puis 3 variables monétaires
nn1,nn2,nn3 is numeric
nn1 = 1.583333
nn2 = 0.9
nn3 = nn1 * nn2

mm1,mm2,mm3 is currency
mm1 = 1.583333
mm2 = 0.9
mm3 = mm1 * mm2


Et bien nn3 vaut 1,424999 alors que mm3 vaut 1,425000

Par comparaison avec CSHARP, le type float qui a 7 chiffres significatifs, on a le comportement suivant :

PUBLIC static string gcs_Test_Compare_Numeric_Currency()
{

string sResult;
float mm1,mm2,mm3;

mm1 = 1.583333F;
mm2 = 0.9F;
mm3 = mm1 * mm2;

sResult = mm3.ToString();

RETURN sResult;

}


renvoie 1.425 comme les monétaires WinDEV, il arrondi.

Je trouve donc le comportement du type numeric WinDEV assez suspect. Qu'en pensez-vous ?
Membre enregistré
21 messages
Posté le 22 mai 2025 - 13:43
Bonjour,

nn1,nn2,nn3 is numeric (*)
nn1 = 1.583333
nn2 = 0.9
nn3 = nn1 * nn2

Trace(nn3) // Renvoi : 1.4249997


Bien cordialement,
Membre enregistré
133 messages
Posté le 22 mai 2025 - 16:36
NN12 a écrit :
> nn1,nn2,nn3 is numeric (*)

Tu n'as pas compris le sujet du topique.
Le sujet du topique est que le type numérique, en dépassement de capacité, fait une troncature, alors que le type monétaire fait un arrondi.
En mettant (*) tu demandes à WinDEV de déplacer sa précision automatiquement, mais le problème de dépassement de capacité se produira pareillement (par exemple sur 5/3).

Le sujet du topique est que un calcul fait en numérique rendra un résultat différent que le même calcul fait en monétaire, alors que l'on s'attendrait à ce que ces deux types résolvent leur dépassement de la même façon.

C'est à mon avis un bug de WinDEV, qui date depuis si longtemps, qu'il ne le corrigeront jamais de peur de planter tous les projets écrits sur cette erreur...
Membre enregistré
21 messages
Posté le 22 mai 2025 - 16:55
Bonjour,
Si tu penses que c'est un bug de la part de PCSoft, je t'invite à leur envoyer un mail au support gratuit.
Ils te répondront plus en détails que nous, qui sommes des développeurs de leur produit.
Bien cordialement,
NN12
Membre enregistré
133 messages
Posté le 05 juin 2025 - 19:27
Bon j'ai avancé un peu sur ce problème.
Il ne faut pas utiliser Trace come l'a dit @Cédric_34. Ni même le débuggeur pas à pas, les nombres affichés ne sont pas les vraies valeurs manipulées en interne.
Il faut utiliser un champ de saisie avec un masque d'affichage ridiculement grand, par exemple
9.999999999999999999999999999999999999999999999999999999999999999999999

Voilà ce que cela donne si l'on range 0,9 dans ce champ :
0,900000000000000022204460492503130808472633361816406250000000000000000


Que l'on mette 0,9 à la main dans le champ de saisie, ou bien par affectation d'un real, currency ou numeric, le champ en sortie affiche systématiquement cette valeur approximative de 0,9

Voilà ce que cela donne si l'on range 1,583333 dans ce champ :
1,583333000000000101437080957111902534961700439453125000000000000000000


La première incohérence apparait lorsque l'on range dans ce champ non pas la valeur 1,583333, mais la valeur en numeric 1583333 / 1000000
Le champ affiche alors une valeur différente.
Pour être plus précis,

1583333 / 1000000
0m1583333 / 0m1000000
0n1583333 / 0n1000000


donnent respectivement

1,583333000000000101437080957111902534961700439453125000000000000000000
1,583333000000000101437080957111902534961700439453125000000000000000000
1,583333000000000323481685882143210619688034057617187500000000000000000


On voit que la divergence apparait lorsque l'on demande au compilateur de faire le calcul entre deux nombres typés numeric.
MAIS cette divergence n'a pas lieu si le calcul est fait non pas à la compilation, mais à l'exécution

nn1,nn2,nn3 is numeric
nn1 = 0n1583333 / 0n1000000
nn2 = 0n9 / 0n10
nn3 = nn1 * nn2
SAI_NUMERICC = nn3

1,583333000000000101437080957111902534961700439453125000000000000000000


Donc vous allez me dire, évitons les calculs à la compilation, et faisons plutôt les calculs à l'exécution dans des variables bien typées ?

Oui mais non, car à l'exécution j'obtiens un écart significatif entre currency et numeric

1.583333 * 0.9 donne respectivement en real, currency, et numeric
1,424999700000000091293372861400712281465530395507812500000000000000000
1,425000000000000044408920985006261616945266723632812500000000000000000
1,424998999999999904630954006279353052377700805664062500000000000000000


En arrondissant à 6 chiffres, cela va donner

1,425000
1,425000
1,424999


Soit une différence de 0,000001, entre le calcul fait en real ou currency, et le calcul fait en numérique.
C'est un bug assez énorme si on réfléchit bien.
Cela ne vient pas du fait que numeric fait une troncature comme je l'avait pensé au début, il fait bien un Arrondi au plus proche, mais sur une base complètement fausse.

Je rappelle que le résultat de 1.583333 * 0.9 est un résultat exact qui vaut 1.4249997

Donc l'erreur faite en real et currency sera de +0,0000003
alors que l'erreur faite en numeric sera de -0,0000007
soit plus du double !