Bug instruction Fix dans VB5

forrestier2003 Messages postés 11 Date d'inscription jeudi 9 février 2006 Statut Membre Dernière intervention 1 mars 2006 - 24 févr. 2006 à 09:51
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 - 1 mars 2006 à 18:50
Bonjour,

Je n'y comprends rien ou est-ce un bug MicroSoft ?

Pour tronquer un nombre positif 2 chiffres après la virgule j'utilisais :
dblA = Fix(dblA * 100) / 100
jusqu'à ce que A soit égal à 267.28 et que j'obtienne 267.27.

Pour débugger mon code j'ai réécrit :

Dim dblA As Double, dblB As Double, dblC As Double, dblD As Double

dblA = 267.28

dblB = dblA * 100 'on obtient 26728
dblC = Fix(dblB) 'on obtient 26727 !!!!!!!!
dblD = dblC / 100 'on obtient 267,27

Une explication ?
Et sur les nouveaux VB ?

14 réponses

cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
24 févr. 2006 à 10:36
Idem en VB6, je cherche s'il y a une explication, c'est probablement les arrondis, j'ai eu ce probleme il y a quelque temps quand j'ai voulu faire la fonction Round de vb6 avec cette méthode.
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
24 févr. 2006 à 10:45
C'est très étrange, fix(100*267,28)=26727
fix(26728)=26728
Idem avec int
0
Vb Lover Messages postés 221 Date d'inscription vendredi 30 novembre 2001 Statut Membre Dernière intervention 13 février 2010 5
24 févr. 2006 à 10:58
tout ça doit reposer sur l'utilisation des Double... par contre, je suis quasiment sûr qu'avec un "Int" au lieu du "Fix", ça doit marcher (je n'ai pas VB sous la main pour vérifier):

int(dblA*100)/100

au pire (mais vraiment en dernier recours), il suffit d'ajouter un petit "epsilon" (aïe aïe, je suis trop mathématicien moi...), du genre:

epsilon = 0.000001
int(dblA*100+epsilon)/100

parce que la précision informatique n'est pas aussi rigoureuse qu'une valeur mathématique exacte...

les maths, c'est tellement plus mieux
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
24 févr. 2006 à 11:41
salut,

FIX arrondi à l'inférieur, INT au supérieur.





Dim dblA As Double, dblB As Double

dblA = 267.28

dblB = (dblA * 100) / 100 'retourne 267,28

dblB = (dblA * 100) \ 100 'retourne 267
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
24 févr. 2006 à 13:16
Chez moi FIX et INT c'est du pareil au même
et sans déclaration en Double sa ne change rien
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
24 févr. 2006 à 14:02
cool .....







çà te donne le même résultat çà?



Const d As Double = -1.9000489



MsgBox Int(d)

MsgBox Fix(d)











MSDN :



<hr size ="2" width= "100%">

[javascript:alink_4.Click() argument] number peut contenir une
valeur de type
<object id ="alink_5" type= "application/x-oleobject" classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11"></object>[javascript:alink_5.Click() Double] ou toute autre
<object id="alink_6" type="application/x-oleobject" classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11"></object>[javascript:alink_6.Click() expression numérique] valide. Si l'argument
number contient une valeur de type
<object id ="alink_7" type="application/x-oleobject" classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11"></object>[javascript:alink_7.Click() Null], Null est renvoyé.



Remarques



Les fonctions Int et Fix suppriment toutes deux la partie
fractionnelle de l'argument number et renvoient l'entier obtenu.



Différence entre les fonctions Int et Fix : si number
est négatif, Int renvoie le premier entier négatif inférieur ou égal à
number, alors que Fix renvoie le premier entier négatif supérieur
ou égal à number. Par exemple, Int convertit -8,4 en -9 et
Fix convertit -8,4 en -8.



Fix(number) équivaut à :


Sgn(number) * Int(Abs(number))
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
24 févr. 2006 à 14:18
Là d'accord quand je disait que int et fix étaient équivalent, je ne le disait que pour ce cas en particulier car 100*267.28 n'est pas négatif. De plus 100*267.28=26728
or int(100*267.28) est différent de int(26728), ce qui est impossible.
Cela revient à dire q'il existe x tel que E(x)<>E(x) alors que la partie entiere à la propriété d'unicité.
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
24 févr. 2006 à 14:57
re-cool...

et depuis quand en programmmation on parle de fonctions qui marchent "pour ce cas" et pas pour d'autres.....



c'est pas important tout çà. la demande de Forrestion2003 portait sur Fix, VbLover a soulevé le point de la différence avec Int, et ci-dessus l'explication MSDN ;)



bonne continuation à tous
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
24 févr. 2006 à 16:30
pcpt, je ne sais pas si c'est volontaire ou bien si c'est une habitude de ne pas répondre aux questions et de déplacer le problème mais quand on te dit qu'il y a un problème pour la valeur 100*267,27
C'est cette valeur qui nous intéresse et -1.9000489 n'a aucun intérêt.
Je le redit avec plus de justesse : pour la valeur qui nous intéresse et qui pose problème la fonction int est équivalente à la fonction fix.
0
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 34
24 févr. 2006 à 16:54
tient ça me rappelle quelque chose !!!!

une certaine source de calcul d'arrondi inférieur, supérieur.







Rappel:

Int(2.3 * 10) donne 22

Int(2.4 * 10) donne 23

Int(2.15 * 100) donne 214



mais:

(2.15 * 100) donne 215

Int(215) donne 215

Daniel
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
24 févr. 2006 à 17:01
C'est pas normal et je ne voit pas d'explication si tu en a une, tu as bien fait de me reparler de ce code je suis allé voir si tu n'avais pas repris un commentaire et je me suis rendu compte que mes variables étaient mal déclarées faute de le faire fonctionner comme Round (parce que sa va me rendre fou) je vais au moins corriger les variables...
0
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 34
24 févr. 2006 à 18:07
l'explication c'est les problèmes de troncation dû au Double

il y a une petite différence (epsilon) entre la valeur réelle et la valeur après transformation en flottant.

par exemple 267,28 serait représenté par 267,279999999999

et Int(26727.999999999) renverrait 26727 (ce qui est logique)



avec du Currency ou du décimal on a la bonne réponse:

ce qui prouve que le problème vient du Double

MsgBox Int(CDbl(267.28) * 100) --> faux

MsgBox Int(CCur(267.28) * 100) --> bon

MsgBox Int(CDec(267.28) * 100) --> bon





- et pourtant il reste quand même un mystère:

si la troncation a lieu pour le Double et pas pour le décimal,

il devrait y avoir une différence entre les deux représentations:



Dim nombre As Double

Dim var As Variant



' si c'était vrai nombre devrait être tronqué à 267.279999999999

nombre = 26728 / 100

' ici la bonne valeur 267.28

var = CDec(26728) / 100

' la différence ne devrait donc pas être zéro ???

MsgBox var - nombre


Daniel
0
forrestier2003 Messages postés 11 Date d'inscription jeudi 9 février 2006 Statut Membre Dernière intervention 1 mars 2006
1 mars 2006 à 18:24
Bonjour,

Je vois que mon problème vous intéresse. Jusqu'à présent la valeur citée est la seule qui me donne un résultat faux. Je n'ai pas pu suivre le déroulé de vos discussions au jour le jour car je suis en vacances et c'est le 1er jour où j'ai accès à Internet. Bien sûr on peut parler d'arrondi, de virgules flottantes, de int et de fix mais tout cela n'est quand même pas normal surtout avec 14 ou 16 chiffres significatifs pour double contre un pauvre nombre de 4 chiffres.
J'avais tourné le problème en convertissant en un string avec Cstr, en déterminant la position du point décimal avec Instr et en prenant le nombre de chiffres nécessaires avec Left puis en reconvertissant en double. Tout cela de mémoire et je pourrai vous donner la procédure exacte samedi soir.

Mais le vrai problème demeure : à quelle instruction VB peut-on se fier ?

Merci pour votre aide.
0
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 34
1 mars 2006 à 18:50
ce que conseille crosoft:

[%27http://support.microsoft.com/default.aspx?scid=kb%3Bfr%3B195657 http://support.microsoft.com/default.aspx?scid=kb%3Bfr%3B195657

]mais j'ai testé, passer par une fonction ça marche toujours pas.


de toute façon la différence existe:

Dim n As Double

n = 267.28

MsgBox 26728 - CDbl(n * 100) '= 3,63797880709171E-12 moins bon

MsgBox 26728 - (n * 100)
'= 2,72848410531878E-12 meilleur

MsgBox 26728 - CDec(n * 100) '=
0

parfait



la vrai différence est en rouge, elle correspond a une différence sur le dernier bit:

exposant 14: 52 - 14 38

2 ^ -38 = 3,63797880709171E-12



il est étonnant de remarquer que le résultat intermédiaire est calculé avec une meilleure précision:

2,72848410531878E-12 = (2 ^ -38) - (2 ^ - 40)



mais Int(27227,99999999...) avec un million de décimales fera toujours 27227



caculer le résultat intermédiare ne sert à rien:

n = n * 100

MsgBox Int(n) --> 27227



par contre en forçant l'arrondi:

n = n * 100

MsgBox Int(CDec(n)) --> 27228



Daniel
0
Rejoignez-nous