Page 1 sur 1

[R] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 17:35
par Sachadee
Bonjour à tous.

J'ai un petit problèmes avec la fonction IsFloat :

On est d'accord que 1.10 * 700 = 770
770 n'est pas une valeur en virgule flottante.

Pourtant si je fais :

Code : Tout sélectionner

Local $Totalproduit = 1.10 * 700
MsgBox("",$Totalproduit,IsFloat($Totalproduit))
ça me retourne 1

Si quelqu'un a une idée....

Re: [..] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 18:22
par jchd
AutoIt effectue une multiplication de double dès lors qu'un des opérandes est double.
Aussi, le résultat d'une division (même 1/1) est aussi un double, éventuellement une forme indéterminée ou un infini.

Code : Tout sélectionner

ConsoleWrite(0/0 & " -> " & VarGetType(0/0) & ", Float? -> " & IsFloat(0/0) & ", Int? -> " & IsInt(0/0) & @LF)
ConsoleWrite(1/0 & " -> " & VarGetType(1/0) & ", Float? -> " & IsFloat(1/0) & ", Int? -> " & IsInt(1/0) & @LF)
ConsoleWrite(-1/0 & " -> " & VarGetType(-1/0) & ", Float? -> " & IsFloat(-1/0) & ", Int? -> " & IsInt(-1/0) & @LF)
ConsoleWrite(1/1 & " -> " & VarGetType(1/1) & ", Float? -> " & IsFloat(1/1) & ", Int? -> " & IsInt(1/1) & @LF)
ConsoleWrite(1.0*3 & " -> " & VarGetType(1.0*3) & ", Float? -> " & IsFloat(1.0*3) & ", Int? -> " & IsInt(1.0*3) & @LF) 

Re: [..] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 18:34
par Sachadee
Merci pour ta réponse.

Mais comment faire pour réinitialiser cette valeur comme "Integer" car même si je fait
un :

Code : Tout sélectionner

Local $Totalproduit = 1.10 * 700
$Test=$TotalProduit*1
MsgBox("",$Test,IsFloat($Test))
$Test hérite apparemment des proprietés de $TotalProduit.

C'est vraiment étrange comme comportement.

Re: [..] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 18:47
par jchd
Tu peux utiliser Int() mais à vrai dire il est rare que cela importe. Pour quelle raison tiens-tu à ce que le produit soit de type Integer ?

Soit dit au passage : IsFloat(1.10 * 700) renvoie 0. <<-- EDIT: pas vrai du tout, j'avais bu !

Je précise que je m'appuie sur la dernière version officielle, ce qui date de 3 ans m'importe peu.

Re: [..] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 19:03
par mikell
Après avoir lu l'avant-dernière réponse de jc tu devrais avoir intégré le fait qu'il y a des mystères qu'il vaut mieux ne pas chercher à comprendre :mrgreen:
Cela dit c'est quand même étonnant que ce souci existe encore
http://www.autoitscript.com/trac/autoit/ticket/1854

Donc a priori

Code : Tout sélectionner

Local $Totalproduit = 1.1*100 

MsgBox(0, $Totalproduit, IsFloat($Totalproduit))
MsgBox(0, $Totalproduit, StringIsFloat($Totalproduit))
:roll:

Edit
IsFloat(1.10 * 700) renvoie bien 1 chez moi (3.3.12.0, dernière release)

Re: [..] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 19:05
par jchd
Oops, pardon. J'ai occulté le fait que 1.10 ne peut être représenté exactement en double.

Re: [..] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 19:12
par mikell
jc ça mériterait pas un ticket staffaire ?

Re: [R] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 19:17
par Sachadee
Effectivement je viens de tester sur la dernière version officiel et ça retourne bien 1. Apparement ce bug est persistent :D

En fait JC mon problème était le suivant. C'est pour un sytème de transfert XML (web service) avec le Fisc Brésilien. Les valeurs doivent avoir un format bien précis (nb de décimale).

Donc je calcule le prix total pour un produit. Si c'est une valeur à virgule flottante je rajoute [00] et si non je rajoute [.00].

Code : Tout sélectionner

If IsFloat($Totalproduit) Then
     $TotalProduit = $Totalproduit & "00"
  Else
     $TotalProduit = $Totalproduit & ".00"
     EndIf
 
et ensuite je recupère la valeur avec juste les 2 dernières décimales.

Code : Tout sélectionner

 $Totalproduit = StringRegExp($Totalproduit, "(\d+[.,]\d{2})",1)
Voilà.

Apparement en remplaçant, comme proposé par Mikell que je remercie grandement, le IsFloat par un StringIsFloat ça fonctionne.


Merci à vous.

Re: [..] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 19:22
par mikell
Ah mais là le problème est différent, il te faut utiliser StringFormat

Code : Tout sélectionner

Local $a = 25
Local $b = 2.5
Local $c = 2.559

MsgBox(0,"",  StringFormat("%.02f", $a) & @crlf & StringFormat("%.02f", $b) & @crlf & StringFormat("%.02f", $c))

Re: [R] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 19:26
par Sachadee
Excellent !

C'est effectivement vraiment plus simple.

Merci.

:wink:

Re: [..] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 19:36
par jchd
Voir ceci ou celà où ma remarque est en avant-dernier post.

Re: [R] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 19:46
par mikell
Sans doute, mais même si le comportement d'Autoit est peut-être techniquement justifié sur le coup (I don't understand its internal behaviour), reste quand même que cette fonction IsFloat() retourne un résultat faux, alors que StringIsFloat() en retourne un exact

Re: [R] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 20:08
par jchd
Faux vs exact : tout est relatif. En réalité ces fonctions sont correctes en ce sens qu'elles satisfont leurs spécifications, celles données dans l'aide.

Code : Tout sélectionner

ConsoleWrite(1.10*700 & " -> " & VarGetType(1.10*700) & ", Float? -> " & IsFloat(1.10*700) & ", Int? -> " & IsInt(1.10*700) & ", Hex = " & Hex(1.10*700) & @LF)

produit :
770 -> Double, Float? -> 1, Int? -> 0, Hex = 4088100000000001 
Donc IsFloat() est correcte (le double possède effectivement une partie décimale).
StringIsFloat() est aussi correcte en ce qu'elle ne détecte pas de partie décimale, car elle disparaît à cause de l'arrondi implicite effectué par la conversion double -> chaîne.

Pour s'en assurer :

Code : Tout sélectionner

ConsoleWrite(StringFormat("%3.16f", 1.10*700) & @LF)

produit :
770.0000000000001100

Re: [R] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 20:26
par jchd
mikell,

Pourquoi remontes-tu ce ticket #1854 ? Le code ne sort rien d'étrange pour moi ?

Re: [R] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 21:25
par mikell
Non non rien à dire avec StringIsFloat, j'ai juste évoqué ce ticket à cause de son titre "StringIsFloat returns 1 on non float numbers" en suggérant que la fonction IsFloat mériterait peut-être un ticket avec un titre équivalent
Je comprends bien que les mécanismes de calcul internes sont particuliers et que ceci peut expliquer cela, mais l'aide disant pour IsFloat : "The function will return 0 if the value is a float with no fractional component (e.g. 1.000)", pour moi qui ne suis pas grand technicien (comme au moins 90% des utilisateurs d'Autoit j'imagine) je traduis bêtement par : cette fonction va me permettre de détecter si un nombre comporte des décimaux ou pas, et dans ce sens tout ça prête vachement à confusion ... dans la mesure où StringIsFloat répond exactement à ce qu'on peut en attendre, on serait en droit de s'interroger sur le fait que IsFloat retourne un résultat différent
Mais si ce fonctionnement est effectivement normal alors il serait plus qu'opportun de mettre un warning dans l'aide (genre "ne pas confondre...")
Le titre du présent topic est une parfaite illustration de cette confusion

Re: [R] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 22:14
par jchd
Malheureusement et tant qu'on persistera à utiliser des flottants binaires, ce genre de souci continuera d'apparaître régulièrement. Mais dans ce cas particulier, on ne doit pas assimiler la partie fractionnaire d'un flottant (sous forme double) avec la présence de décimales lors de sa conversion implicite en chaîne.

Il est logique d'afficher (donc sous forme chaîne) 1.10 * 700 et qu'on voie 770 et il est tout aussi cohérent qu'un test du résultat avec IsFloat (donc un test portant sur un type double) nous informe que ce n'est pas un entier exact, puisque 1.1 ne peut pas être représenté exactement par un double.

StringIsFloat demande un paramètre chaîne, ce qui implique une conversion interne de double vers chaîne, conversion qui pratique un arrondi salvateur dans la plupart des situations. On aurait bien plus de hurlements (à juste titre AMHA) si ConsoleWrite(1.10*700) affichait 770.000000000000110

Une note dans l'aide ne servirait guère : l'aide sur le détail des types et autre "Language Reference" n'est que rarement consultée. 99% des gens postent leur désaroi lorsqu'ils rencontrent un tel problème, ayant implicitement espéré que les opérations flottantes (binaires) puissent refléter exactement les opérations décimales auxquelles nous sommes habitués depuis notre plus tendre enfance.

ConsoleWrite(StringFormat("%3.16f", 1.1*1.3) & @LF) --> 1.4300000000000002
D'où diable sort donc ce 2 ?

ConsoleWrite(StringFormat("%3.16f", 1.4) & @LF) --> 1.3999999999999999
J'avais pourtant bien dit 1.4, non ?

Re: [R] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 22:59
par mikell
Moui... et pour vérifier qu'un nombre (pas une string !) est un entier on utilise IsInt (et pas StringIsInt) alors que pour vérifier s'il a des décimales c'est StringIsFloat (et pas IsFloat)
Tout ça est limpide mais pas vraiment clair (et réciproquement)
Comment tu veux que le béotien que je suis, il s'y retrouve ? :mrgreen:

Re: [R] Problème avec la fonction IsFloat

Posté : jeu. 10 juil. 2014 23:31
par jchd
Tout dépend du sens que tu donnes à "avoir des décimales".
Si tu penses aux éventuelles décimales qui apparaîtraient même après conversion en chaîne, c'est StringIsFloat.
Si tu t'intéresses aux décimales de haut rang (genre 1e-14) qu'on néglige la plupart du temps, c'est IsFloat, IsInt ou Frac.

Re: [R] Problème avec la fonction IsFloat

Posté : ven. 11 juil. 2014 00:19
par Sachadee
Tout dépend du sens que tu donnes à "avoir des décimales".
Si tu penses aux éventuelles décimales qui apparaîtraient même après conversion en chaîne, c'est StringIsFloat.
Si tu t'intéresses aux décimales de haut rang (genre 1e-14) qu'on néglige la plupart du temps, c'est IsFloat, IsInt ou Frac.
Là ça devient bien plus clair.

Merci.