Page 1 sur 2
Demande d'aide avec ValD()
Publié : ven. 10/juin/2011 16:36
par MetalOS
Salut tous le monde,
Pour mon projet j'ai besoin de récupérer le contenue de plusieurs StringGadget() afin de les convertir en valeur numérique. J'utilise pour ca la commande VaiD(). Seulement le résultat n'est celui que j'attendais. Faite un test avec ca:
Resultat.d n'est pas égale à 10.000024 mais à 10.00002384185791015625
Vous savez comment obtenir aux chiffres près le contenue de mes StringGadget() ? Merci d'avance.
PS/ Je pense que la solution doit être simple, mais je voie franchement pas

Re: Demande d'aide avec ValD()
Publié : ven. 10/juin/2011 16:48
par nash
resultat correct (10.000024)
sous windows vista 32 bits
preference /valeur par default /utf-8
je ne peux tester sous ubuntu (j'apprend)
ni sous windows 7
Re: Demande d'aide avec ValD()
Publié : ven. 10/juin/2011 16:49
par Chris
Ça marche chez moi avec le code que tu donnes. (XPSP3 - Pb 4.51)
Résultat du debugger
10.000024
Re: Demande d'aide avec ValD()
Publié : ven. 10/juin/2011 16:52
par MetalOS
Bizarre que sous Ubuntu ca me donne un autre résultat

Re: Demande d'aide avec ValD()
Publié : ven. 10/juin/2011 17:02
par MetalOS
Je vient de tester sous PB 4.60 beta 3 et même chose

Les systèmes UNIX/Linux sont peut être plus précis en conversion que sous Windows ?
Re: Demande d'aide avec ValD()
Publié : ven. 10/juin/2011 17:09
par nash
je pense a mon avis que si l'on demande
au debogueur de donner "10.000024"
sans calcul(+/*- etc..)
il doit donner comme resultat "10.000024"
cela dans tous les systeme d'exploitation
mais peut etre je me trompe
Re: Demande d'aide avec ValD()
Publié : ven. 10/juin/2011 17:12
par graph100
J'invite tout le monde à regarder le code suivant :
Code : Tout sélectionner
Resultat.d = (ValD("10.000024") - 10 )
Debug Resultat + 10
Debug Resultat * 100000000
Debug Resultat * 10000000
Debug Resultat * 1000000
Debug Resultat * 100000
Debug Resultat * 10000
Debug Resultat * 1000
je vous invite aussi à lire dans la documentation de PureBasic :
Aide PureBasic, section : Variables, Types et Opérateurs a écrit :Informations concernant les nombres flottants
Un nombre flottant est stocké de telle manière que la 'virgule flotte' autour de la partie réelle. De la sorte, il est possible d'avoir des nombres dont la valeur peut être aussi bien grande que petite. Toutefois vous ne pouvez pas stocker de grands nombres avec une précision aussi élevée que des petits nombres.
Une autre limitation concernant les nombres flottants est qu'ils restent concrètement représentés sous une forme binaire. Ainsi, ils ne peuvent être restitués qu'à partir de multiples et de divisions en base 2. Celà est important pour comprendre que la représentation décimale lors de l'affichage ou du calcul n'est pas tout à fait identique à ce que l'on peut attendre dans une représentation humaine. Représenter 0.5 ou 0.125 est simple car ce sont des divisions parfaites de 2, cela est plus complexe pour des nombres comme 0.11 ou 0.10999999. L'affichage approché de la valeur est toujours correct à un nombre limité de décimales, mais ne soyez pas surpris si au-delà le nombre affiché s'écarte de la valeur que vous attendez!
Ces remarques s'appliquent aux nombres flottants traités par ordinateur d'une manière générale et non spécifiquement à Purebasic.
Comme leur nom l'indique, les 'doubles' sont des flottants 'double-precision' (64 bits) comparativement aux flottants 'simple-precision' que sont les floats (32 bits). Donc, pour avoir plus de précision dans la manipulation des nombres à virgule, il est préférable d'utiliser les 'doubles'.
Pour plus d'information sur le format 'IEEE 754', consulter l'article Wikipedia.
Re: Demande d'aide avec ValD()
Publié : ven. 10/juin/2011 17:50
par MetalOS
Comment faire alors pour obtenir le même résultat sous Ubuntu que sous Windows ?
Re: Demande d'aide avec ValD()
Publié : ven. 10/juin/2011 20:46
par G-Rom
tu as un ubuntu 64bits c'est sur... sur un 32bits , que tu soit sous linux/mac/windows , tu obtiens le même résultat.
Re: Demande d'aide avec ValD()
Publié : ven. 10/juin/2011 20:56
par falsam
Avec ce code que j'ai testé sous window 7 et Ubuntu tu devrais obtenir le même résultat (10.000024).
Code : Tout sélectionner
Procedure.s RoundX(Value.d, Decimal.w)
Protected Number.d
Number= Int(Value * Pow(10, Decimal) + 0.5) / Pow(10, Decimal)
ProcedureReturn StrD(Number, Decimal)
EndProcedure
Debug RoundX(10.000024, 6)
Pourquoi cette procédure ?
Debug RoundX(10.0000244, 6) donnera 10.000024
Debug RoundX(10.0000245, 6) donnera 10.000025
Voila voila ...
Re: Demande d'aide avec ValD()
Publié : ven. 10/juin/2011 22:49
par anissa
Bonjour
C'est un sujet qui m'intéresse beaucoup, on en a déjà parlé et j'ai même précisé que ce problème persiste et ne sera jamais réglé par une simple ValD(X$) ça ne donnera jamais ce qu'on veut.
La solution la plus sûre c'est de créer des petites procédures pour régler ce genre de problème.
Je l'ai déjà fait et ça marche très bien. Il s'agit de créer des procédures bien distinctes car le string peut très bien contenir n'importe quel type de numérique (entier, décimal avec 1,2,3,4.. décimaux etc..) Voici en tout cas ce que j'ai fait et ce que je continue à faire jusqu'à présent.
Code : Tout sélectionner
Global wstring$, WMsg$,WLeft$, Wright$,wDecim$, WNew$, wVal$, Wsauve$
Global wtaille,WPos,wNbDecim, ErrorFound
Global Z,K$,i,j,k,DIM wCar$(30)
;-------------------------------- Conversion Entier vers Décimal ----------------------
Procedure Convertir_En_D()
;Enlever les espaces des milliers (éventuellement ex: 258 114 devient 258114)
WNew$=""
Wstring$=Trim(wString$)
For i=1 To Len(Wstring$)
WVal$=Mid(Wstring$,i,1)
If WVal$<>""
WNew$=WNew$+wVal$
EndIf
Next i
Wstring$=Trim(wnew$)
Wtaille=Len(wString$)
;Cas où le nbre est trop petit (ex: 1 centième)
If wtaille=1 : wString$="0.0" + Trim(wString$): EndIf
If wtaille=2 : wString$="0." + Trim(wString$): EndIf
If wtaille>2
WLeft$=Left(wString$,wtaille-2)
wDecim$=Right(wString$,2)
wString$=Trim(WLeft$+"."+wDecim$)
EndIf
If ValQ(wString$)=0 : wString$="0.00" : EndIf
If Left(wString$,1)="." Or Left(wString$,1)="," : wString$="0"+wString$ : EndIf
Wstring$=Trim(wString$)
EndProcedure
;-------------------------------- Conversion Décimal vers Entier ----------------------
Procedure Convertir_En_E()
WPos= FindString(Wstring$, ",", 1)
If wpos=0
wPos= FindString(Wstring$, ".", 1)
EndIf
If wpos=0
Wstring$=Wstring$+"00"
Else
wDecim$=Mid(Wstring$,wpos+1,2)
wLeft$=Left(Wstring$,wpos-1)
wRight$=LSet(wDecim$,2,"0")
Wstring$=Trim(wLeft$)+Trim(wRight$)
EndIf
Wstring$=Trim(wString$)
EndProcedure
;-------------------------------- Séparer numeric en milliers --------------------
Procedure Separer_Numeric_En_Millier()
;Enlever éventuellement les espaces internes
Wsauve$=""
wstring$=Trim(wstring$)
Wtaille=Len(wstring$)
For i=1 To wtaille
If Mid(wstring$,i,1)<>Space(1)
Wsauve$=Wsauve$+ Mid(wstring$,i,1)
EndIf
Next i
wstring$=Trim(wsauve$)
For i=1 To 22 : wCar$(i)="" : Next i
i=22
Wtaille=Len(wstring$)
wRight$=""
If Mid(wString$,wtaille-2,1)="." Or Mid(wString$,wtaille-2,1)=","
wRight$=Space(1) + Right(wstring$,6)
wtaille=wtaille-6
EndIf
While i>0
For j=1 To 3
If wtaille>0
wCar$(i)=Mid(wString$,wtaille,1)
wtaille=wtaille-1
i=i-1
EndIf
If wtaille<=0
Break
EndIf
Next j
i=i-1
If i>0
wCar$(i)=Space(1)
i=i-1
EndIf
Wend
wstring$=""
For i=1 To 22
wstring$=wstring$+wCar$(i)
Next i
wstring$=wstring$+wright$
wstring$=Trim(wstring$)
EndProcedure
;-------------------------------- Test si Numérique --------------------
Procedure IsNumeric(wString$)
wString$=Trim(wString$)
wTaille=Len(wString$)
wNbDecim=0
k$=""
Result=0
For z=1 To wTaille
k$=Mid(wString$,z,1)
If k$="1" Or k$="2" Or k$="3" Or k$="4" Or k$="5" Or k$="6" Or k$="7" Or k$="8" Or k$="9" Or k$="0" Or k$="," Or k$="."
Result=1
Else
Result=0
Break
EndIf
If k$="," Or k$="."
wNbDecim=wNbDecim+1
If wNbDecim>1
Result=0
Break
EndIf
EndIf
Next z
ProcedureReturn Result
EndProcedure
;-------------------------------- Test si NbreDécimal --------------------
Procedure NbreDecimal(wString$)
wString$=Trim(wString$)
wTaille=Len(wString$)
wNbDecim=0
k$=""
Result=0
For z=1 To wTaille
k$=Mid(wString$,z,1)
If k$="1" Or k$="2" Or k$="3" Or k$="4" Or k$="5" Or k$="6" Or k$="7" Or k$="8" Or k$="9" Or k$="0" Or k$="," Or k$="."
Result=1
Else
Result=0
Break
EndIf
If k$="," Or k$="."
wNbDecim=wNbDecim+1
If wNbDecim>1
Result=0
Break
EndIf
EndIf
Next z
ProcedureReturn Result
EndProcedure
;-------------------------------- Test si NbreEntier --------------------
Procedure NbreEntier(wString$)
wString$=Trim(wString$)
wTaille=Len(wString$)
k$=""
Result=0
For z=1 To wTaille
k$=Mid(wString$,z,1)
If k$="1" Or k$="2" Or k$="3" Or k$="4" Or k$="5" Or k$="6" Or k$="7" Or k$="8" Or k$="9" Or k$="0"
Result=1
Else
Result=0
Break
EndIf
Next z
ProcedureReturn Result
EndProcedure
;-------------------------------- Caractères de nom de champ valide?----------------------
Procedure InvalidName(wString$)
wstring$=Trim(wstring$)
Result=0
wPos= FindString(Wstring$, ",", 1)
If wpos=0
wPos= FindString(Wstring$, ".", 1)
EndIf
If wpos=0
wPos= FindString(Wstring$, Space(1), 1)
EndIf
If wpos<>0
Result=1
EndIf
ProcedureReturn Result
EndProcedure
;***************************************************************
; TEST
;*************************************************************
;Tester si la chaîne est correcte (type quelconque mais correct)
WString$=getGadGetText(#Chaîne)
;1. Je teste si cette chaîne contient des caractères valides d'abord
IF InvalidName(wString$)
wMsg$="Chaîne incorrecte !"
Goto Retour
EndIF
;2. Je teste si cette chaîne est numérique
IF not IsNumeric(wString$)
wMsg$="Chaîne non numérique !"
Goto Retour
EndIF
;3. Je teste s'il s'agit d'un entier
IF NbreEntier(wString$)
wMsg$="C'est un entier !"
EndIF
;4. Je teste s'il s'agit d'un nombre décimal
IF NbreDecimal(wString$)
wMsg$="C'est un nbre décimal !"
EndIF
;A PARTIR D'ICI JE PEUX FAIRE CE QUE JE VEUX AVEC MA VARIABLE
;Si j'ai un entier (je le sais maintenant), et que je veux l'afficher en séparant les milliers
; Exemple : 15823 devient 15 823, il suffit de faire ceci:
Separer_Numeric_En_Millier()
DeBug wString$
;Si je veux récupérer exactement les mêmes caractères du champ de saisie
; on a qu'à utiliser directement Wstring$ (sans conversion)
; exemple: Wstring$="10.000024"
;Si maintenant je veux travailler avec ce nombre, il suffit de le transférer directement
;dans la variable double (ou float):
MaVar.D= Wstring$
;Si je veux faire des calculs avec prise en charge de toutes les décimales on fera :
; a) Convertir ce nbre en entier
;(La procédure de conversion travaille avec 0 à 2 décimaux, donc ici je dois récupérer le reste des décimaux :)
WTaille=len(wstring$)
Wreste$=right(Wstring$,4) (on peut généraliser ce nbre 4)
WNbre$=left(wstring$,wtaille-4)
wstring$=WNbre$
Convertir_En_Entier()
Debug wstring$ (qui doit donner: "1000")
;On ajoute les autres décimaux
wstring$=wstring$=+Wreste$
Debug wstring$ (qui doit donner: "10000024")
;A partir de là je crois qu'on peux faire ce qu'on veut avec ce nbre
De toute façon c'est juste une exemple mais je sais qu'il doit y avoir d'autres solutions
Re: Demande d'aide avec ValD()
Publié : ven. 10/juin/2011 23:06
par graph100
oui, avec les chaines on n'a plus de problème. Il y a juste un minuscule problème de lenteur à l'exécution

Re: Demande d'aide avec ValD()
Publié : sam. 11/juin/2011 7:13
par Le Soldat Inconnu
Un nombre flottant ne peut être juste que un nombre de cas assez réduit.
C'est le principe même d'un nombre flottant.
Cela vient du binaire
un nombre binaire se code comme cela par exemple :
7 = 1 * 2^0 + 1 * 2^1 + 1 * 2^2 soit 111
9 = 1 * 2^0 + 0 * 2^1 + 0 * 2^2 + 1 * 2^3 soit 1001
bit 0 correspond à x * 2^0
bit 1 correspond à x * 2^1
bit 2 correspond à x * 2^2
bit 3 correspond à x * 2^3
etc ...
Pour passer en dessous de la virgule, on passe en exposant négatif
0.5 = 1 * 2^-1 soit 0.1 en binaire
2.75 = 1 * 2^-2 + 1 * 2^-1 + 0 * 2^0 + 1 * 2^1 soit 10.11
Maintenant,je prend un nombre plus compliqué style
0.79 = ?
1 * 2^-2 + 1 * 2^-1 je suis à 0.75, manque 0.04
1 * 2^-5, ça fait 0.03125
je suis à 0.78125, manque encore 0.00875
1 * 2^-7 = 0.0078125
je suis à 0.7890625, manque encore 0.0009375
1 * 2 ^-11 = 0.00048828125
je suis à 0.78955078125 et il me manque encore 0.00044921875
bref, je pas encore sorti du bazar
je me suis arrêté à 16 bits
0 , 1 1 0 0 1 0 1 0 0 0 1 1 1 1 0
Et je ne suis toujours pas juste, j'en suis à 0,789978027.
Est-ce que tu comprend maintenant pourquoi ton nombre ne sera pas juste en flottant ?
Re: Demande d'aide avec ValD()
Publié : sam. 11/juin/2011 14:43
par nash
C'est bizarre que ubuntu
reagit avec vald("10.000024")
qui avec window donne bien 10.000024
en donnant 10.00002384185791015625
alors qu'il donne avec ce systeme
approximativement ce nombre mais avec
valf(float)
interessante explication de LSI
Re: Demande d'aide avec ValD()
Publié : sam. 11/juin/2011 14:49
par G-Rom
il n'y a rien de bizarre , cela n'a rien à voir avec l'OS , mais avec vos processeurs et le format 'IEEE 754' .