Page 1 sur 1

Petit problème de Float

Publié : jeu. 24/janv./2013 17:55
par Torp
Voici un petit exemple de mon souci :

Code : Tout sélectionner

a.f = 21.3
b.f = 2.65
c.f = a-2*b

d.f = 16.0

If c = d
	Debug "égal"
ElseIf d < c
	Debug "inférieur"
ElseIf d > c
	Debug "supérieur"
EndIf
Le résultat devrait être "égal" mais ce n'est pas le cas... Comment puis-je contourner cette limitation "informatique" de manière simple et fiable ?

Merci,
Bye

Re: Petit problème de Float

Publié : jeu. 24/janv./2013 18:05
par graph100
utilise des double : .d

et c'est normal qu'avec des float ce ne soit pas égal. (lit l'aide de PB dans la section "Variables, Types et Opérateurs"
Il vaudrait mieux ne jamais faire des tests d'égalité avec des nombres à virgule.

Re: Petit problème de Float

Publié : jeu. 24/janv./2013 20:05
par Ar-S
Tu peux éventuellement fixer le nombre de décimale.

Code : Tout sélectionner

a.f = 21.3
b.f = 2.65
c.f = a-2*b

d.f = 16.0

Fixed_c.f = StrF(c,5)
Fixed_d.f = StrF(d,5)

If Fixed_c = Fixed_d
		Debug "égal"
ElseIf Fixed_c > Fixed_d
		Debug "supérieur"
ElseIf Fixed_c < Fixed_d
		Debug "Inferieur"
EndIf

------edit-----

La remarque de graph100 me parait plus censée

Re: Petit problème de Float

Publié : jeu. 24/janv./2013 20:12
par GallyHC
Ouep j'ai testé avec ce que disait "graph100" et cela fonctionne, voir l'exemple :

Code : Tout sélectionner

a.d = 21.3
b.d = 2.65
c.d = a - (2 * b)

d.f = 16.0

If c = d
   Debug "égal"
ElseIf d < c
   Debug "inférieur"
ElseIf d > c
   Debug "supérieur"
EndIf
Cordialement,
GallyHC

Re: Petit problème de Float

Publié : jeu. 24/janv./2013 23:17
par Fred
C'est parce que c'est pas égal, tout simplement :)

Code : Tout sélectionner

a.f = 21.3
b.f = 2.65
c.f = a-2*b

d.f = 16.0

Debug c
Debug d

Re: Petit problème de Float

Publié : ven. 25/janv./2013 0:12
par graph100
Fred a écrit :C'est parce que c'est pas égal, tout simplement :)

Code : Tout sélectionner

a.f = 21.3
b.f = 2.65
c.f = a-2*b

d.f = 16.0

Debug c
Debug d
Eh oui, mais pour le comprendre il faut qu'il lise cette page de l'aide de PureBasic (tout en bas) :D

@GallyHC : j'avais testé quand même :mrgreen:
@Ar-S : Ta méthode fonctionne, mais je pense qu'il serait plus adéquate de mettre un intervalle plutôt que de passer par des string

Tiens, je me suis amusé à comparer les vitesses d'exécutions entre les différentes méthodes.
Conclusion (sans faire de tests ANOVA) : l'utilisation de chaine est 1000 fois plus lente que les méthodes numériques.
Mais entre les autres méthodes, il n'apparait pas de différences significatives.
Ma préférence irai vers la macro avec ABS()

Code : Tout sélectionner

DisableDebugger
_Debug$ = ""

Macro IS_EGAL(nb1, nb2, intervalle)
	(Abs(nb1 - nb2) <= intervalle * 1.1)
EndMacro

Macro IS_EGAL1(nb1, nb2, intervalle)
	(nb1 - intervalle <= nb2) And (nb1 + intervalle >= nb2)
EndMacro

Macro IS_EGAL_STRING(nb1, nb2, nb_dec)
	StrF(nb1, nb_dec) = StrF(nb2, nb_dec)
EndMacro


a.f = 21.3
b.f = 2.65
c.f = a-2*b

d.f = 16.0

_Debug$ + #CR$ + StrF(c)
_Debug$ + #CR$ + StrF(d)

If IS_EGAL(c, d, 0.01)
	_Debug$ + #CR$ + "EGAL"
Else
	_Debug$ + #CR$ + "Inégal"
EndIf

_Debug$ + #CR$ + ""
_Debug$ + #CR$ + "autre test"
_Debug$ + #CR$ + ""

c = 165.356
d = 165.355

_Debug$ + #CR$ + StrF(c)
_Debug$ + #CR$ + StrF(d)

If IS_EGAL(c, d, 0.001)
	_Debug$ + #CR$ + "EGAL à 0,001 près"
Else
	_Debug$ + #CR$ + "Inégal"
EndIf

If IS_EGAL1(c, d, 0.001)
	_Debug$ + #CR$ + "EGAL à 0,001 près"
Else
	_Debug$ + #CR$ + "Inégal"
EndIf

If IS_EGAL_STRING(c, d, 3)
	_Debug$ + #CR$ + "EGAL à 3 decimales près"
Else
	_Debug$ + #CR$ + "Inégal"
EndIf


If IS_EGAL(c, d, 0.0001)
	_Debug$ + #CR$ + "EGAL à 0,0001 près"
Else
	_Debug$ + #CR$ + "Inégal"
EndIf

nb = 1000000000

t = ElapsedMilliseconds()
For i = 0 To nb
	If IS_EGAL(c, d, 0.0001)
		
	Else
		
	EndIf
Next
_Debug$ + #CR$ + "1 000 000 000 de tests : Macro : ABS()  " + Str(ElapsedMilliseconds()-t)


t = ElapsedMilliseconds()
For i = 0 To nb
	If IS_EGAL1(c, d, 0.0001)
		
	Else
		
	EndIf
Next
_Debug$ + #CR$ + "1 000 000 000 de tests : Macro : <= et >=  " + Str(ElapsedMilliseconds()-t)


t = ElapsedMilliseconds()
For i = 0 To nb
	If c = d
		
	Else
		
	EndIf
Next
_Debug$ + #CR$ + "1 000 000 000 de tests : référence  " + Str(ElapsedMilliseconds()-t)


t = ElapsedMilliseconds()
For i = 0 To 1000000
	If IS_EGAL_STRING(c, d, 3)
		
	Else
		
	EndIf
Next
_Debug$ + #CR$ + "    1 000 000 de tests : Macro : strf()  " + Str(ElapsedMilliseconds()-t)


MessageRequester("", _Debug$)

Re: Petit problème de Float

Publié : ven. 25/janv./2013 10:45
par Torp
Fred a écrit :C'est parce que c'est pas égal, tout simplement :)
Oui c'est un façon de voir les choses... Disons que "en informatique" cela n'est pas égal, mais pour le commun des mortels cela l'est :D

Merci pour votre aide.
Pour info, j'avais bien lu l'aide de PB... Mais je n'avais jamais rencontré le problème vicieux que cela pouvait poser... J'ai fait une Calculatrice (http://www.app-art.fr/phicalculator/index.html) dans le cadre de mon boulot que nous nous servons depuis 2 ans et hier, c'est un utilisateur qui m'a remonté un problème d'incohérences de résultats dans un cas bien précis de valeurs saisies, où le test d'égalité foire...

Par contre pourquoi le type double ne pose pas le même problème ?

Re: Petit problème de Float

Publié : ven. 25/janv./2013 12:01
par Backup
Torp a écrit :Par contre pourquoi le type double ne pose pas le même problème ?
logiquement, je suppose que ton nombre "Rentre" dans un Double ..

mais si tu utilises des nombres qui ne rentre pas (qui depasse la capacité) d'un Double tu aura le meme soucis ..

( ça me rappel le Test Hebdogiciel ... ;) )

Re: Petit problème de Float

Publié : ven. 25/janv./2013 12:11
par Torp
Ben en fait je viens de vérifier le type double pose les même problèmes mais pas au même moments... ce qui est logique.

Du coup comme l'a dit Graph100 les test d'égalité avec les nombres à virgules sont un peu comme la roulette russe.

Edit : Voilà ce qu'explique Microsoft (solution utilisée par Graph100 un peu plus haut) :

Code : Tout sélectionner

Pour tester de manière fiable l'égalité en virgule flottante (dans n'importe quel format en virgule flottante binaire, telles que IEEE ou au Format binaire Microsoft), vous devez soustraire deux nombres à virgule flottante qui sont comparés et vérifier si leur différence est inférieure à une valeur dans les limites de leur importance pour simple ou double précision.