Page 1 sur 1
Arrondi sur flottant
Publié : mar. 06/nov./2007 11:55
par Ulix
Bonjour a tous !
Voilà ma question :
Comment faire pour arrondir un nombre.f avec seulement deux chiffres significatif après la virgule, le reste étant a 00000000 ?
Je m'explique, je lis un fichier en mode texte, des sommes y sont sous la forme suivantes : 36.48
Je convertis cette chaine de caractaire avec l'instruction : ValF( ), j'obtiens donc un flottant = 36.47999954223633
Je que je désire c'est obtenir ça : 36.48000000000000
Comment faire cela ?
La seule instruction pouvant arrondir, Round(Nombre.f, Mode), ne permet pas de d'arrondir par exemple a deux chiffre après la virgule !
Cela m'inspire la réflexion suivante; qu'un type Monétaire sur les variables ne serait pas superflu !
Bref, quelqu'un a-t-il une solution ?
Merci d'avance !

Re: Arrondi sur flottant
Publié : mar. 06/nov./2007 12:45
par Backup
Ulix a écrit :Bonjour a tous !
Voilà ma question :
Comment faire pour arrondir un nombre.f avec seulement deux chiffres significatif après la virgule, le reste étant a 00000000 ?
tu te rapelle de la fonction Print using ou l'on specifiait le masque a afficher avec des #### ??
ben Good07 nous avait fait ça, et ça marche plutot tres bien
Code : Tout sélectionner
;Simulation de Print Using
;Auteur Good07
;Pure Basic version 3.94
;Octobre 2005
Procedure Using(PosX,PosY,masque.s,nombre.s)
PosDeciMasque=FindString(masque,".",1); position du point décimal du masque
PosDeciNombre=FindString(nombre,".",1); position du point décimal du nombre (si pas de décimale renvoi zéro)
MasqueDroite=Len(masque)-PosDeciMasque ; récupère le nombre de chiffre à droite du point décimal du masque
MasqueGauche=Len(masque)-(MasqueDroite+1); idem à gauche
PartieEntiere.s=Mid(nombre,1,PosDeciNombre-1); récupère la partie entière du nombre
PartieDecimale.s=Right(nombre,Len(nombre)-PosDeciNombre); idem pour la partie décimale
If PosDeciNombre=0
drnombre.s=LSet(".",MasqueDroite+1,"0"); si le nombre n'est pas décimal, rajoute un point + le nombre de zéro correspondants au masque
Else
drnombre.s="."+Left(PartieDecimale,MasqueDroite); si décimal coupe la partie décimale à afficher en fonction du masque
EndIf
Format$=RSet(Right(PartieEntiere,MasqueGauche),MasqueGauche," ")+drnombre; met le nombre au format
StartDrawing(WindowOutput())
DrawingMode(1)
LongMasque=TextLength(masque); On récupère la longueur du masque en pixels
PosChaine=LongMasque-TextLength(Format$); modifie la position d'affichage qui est différente suivant la police utilisée.
Locate(PosX+PosChaine,PosY)
DrawText(Format$)
StopDrawing()
EndProcedure
If OpenWindow(0, 0, 0, 600, 400, #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget, "Test Print Using") = 0 Or CreateGadgetList(WindowID()) = 0
End
EndIf
;-------------------------------------Exemple d'affichage
StartDrawing(WindowOutput())
DrawingMode(1)
Restore nombre
Locate(10,10)
DrawText("Affichage sans Print Using")
For i=1 To 10
Read n.f
res.s=StrF(n)
Locate(10,30+pasy)
DrawText(res)
pasy+20
Next i
Locate(300,10)
DrawText("Affichage avec Print Using")
StopDrawing()
Restore nombre
For yy=30 To 210 Step 20
Read n.f
res.s=StrF(n)
Using(300,yy,"######.##",res); appel de la procedure: on donne le masque de formatage et le nombre à formater.
Next yy
Repeat
Event = WaitWindowEvent()
Until Event = #PB_EventCloseWindow
End
DataSection
nombre:
Data.f 12.56364,1456.23,243676.12,789,18.475,145.89,3.14159265,45,4561,478
; IDE Options = PureBasic v3.94 (Windows - x86)
Publié : mar. 06/nov./2007 12:48
par cederavic
euh....
Resultat$ = StrF(Valeur.f [, NombreDeDecimales])
Resultat$ = LSet(Chaine$, Longueur [, Caractere$])
et...
euh...
EDIT : Bouerf j'ai lu trop vite et pris le problème à l'envers, désolé. La soluce de dobro est parfaite

Publié : mar. 06/nov./2007 16:22
par Ulix
Merci pour vos réponses, mais je crois que je me suis mal expliqué !
Mon problème n'est pas l'affichage, mais plutôt la représentation mémoire de la variable !
La conversion chaine-flottant entraine une imprécision le 36.48 devient : 36.47999954223633
Cette imprécision, dans des calculs pourtant simple (ex : multiplication) s'accroit, certes c'est faible, mais préfèrerais avoir après la conversion 36.48000000000000.
Y a t-il un moyen comblé (ou de remplacé) ces chiffres non significatif (surtout pour du monétaire) par des zéro ?
Publié : mar. 06/nov./2007 18:12
par Backup
c'est vrais que VALF() manque un parametre pour ne tenir compte que de x chiffres apres la virgule, là nous avons tout ou rien !

Publié : mar. 06/nov./2007 18:15
par Dr. Dri
ca marche pas ca ? tu manipules tes nombres normalement et tu les affiche/enregistre sous cette forme... tu n'auras jamais de valeur exacte sauf cas particuliers (0.5, 0.25 etc)
Dri
Publié : mar. 06/nov./2007 18:25
par Backup
Dr. Dri a écrit :ca marche pas ca ? tu manipules tes nombres normalement et tu les affiche/enregistre sous cette forme... tu n'auras jamais de valeur exacte sauf cas particuliers (0.5, 0.25 etc)
Dri
oui mais la valeur Flottant dans une variable flottante reprendra l'imprecision !!
si tu fait
Code : Tout sélectionner
b.s=StrF(36.48 , 2)
Debug b.s
; ok il est arrondi
a.f=ValF(b.s)
Debug a.f
; la valeur interne de la variable est toujours imprecise !!
; et perd l'arrondi !!!
seul les variable chaines garde les arrondis !!!

Publié : mar. 06/nov./2007 18:33
par Ulix
Désoler Dr.Dri !
Mon problème n'est pas l'affichage, mais plutôt la représentation mémoire de la variable !
La conversion chaine-flottant entraine une imprécision le 36.48 devient : 36.47999954223633
Je désirerais que le nombre.f soit égale a 36.48000000000000
Dobro a écrit
; la valeur interne de la variable est toujours imprecise !!
; et perd l'arrondi !!!
Tout a fait exacte !
Merci quand même

Publié : mar. 06/nov./2007 18:45
par case
une solution serait de conserver des strings en mémoire
et de ne pas les convertir en float pour les calculs
mais d'effectuer les calculs 'a la main ' de la même façon qu'a l'école ^^
voila un début de solution addition et multiplications ne geres pas les nombres negatifs
Code : Tout sélectionner
Declare.s multiply(st1$,st2$)
Declare.s addition(st1$,st2$)
Declare.s soustraction(st1$,st2$)
Debug multiply("20.5","35.0")
Debug addition("20.2","35.58")
Procedure.s multiply(st1$,st2$)
V1=Len(st1$)-FindString(st1$,".",1) ; nombre de decimales
V2=Len(st2$)-FindString(st2$,".",1) ; nombre de decimale
If v1=Len(st1$):v1=0:EndIf
If v2=Len(st2$):v2=0:EndIf
st1$=RemoveString(st1$,".")
st2$=RemoveString(st2$,".")
;multiplication
result$=Str(Val(st1$)*Val(st2$))
result$=(Left(result$,Len(result$)-(V1+V2))+"."+Right(result$,(v1+v2)))
ProcedureReturn result$
EndProcedure
Procedure.s addition(st1$,st2$)
V1=Len(st1$)-FindString(st1$,".",1) ; nombre de decimales
V2=Len(st2$)-FindString(st2$,".",1) ; nombre de decimale
;
If v1=Len(st1$):v1=0:EndIf
If v2=Len(st2$):v2=0:EndIf
If v2<>V1
If v1>V2
If v2=0 ; pas de virgule
st2$=st2$+"."+Space(V1-v2)
Else
st2$=st2$+"."+Space(V1-v2)
EndIf
EndIf
If v2>v1
If v1=0 ; pas de virgule
st1$=st1$+Space(V2-v1)
Else
st1$=st1$+Space(V2-v1)
EndIf
EndIf
EndIf
If Len(st1$)>Len(st2$)
st2$=Space(Len(st1$)-Len(st2$))+st2$
EndIf
If Len(st2$)>Len(st1$)
st1$=Space(Len(st2$)-Len(st1$))+st1$
EndIf
ret=0
For a=Len(st1$) To 1 Step -1
If Mid(st1$,a,1)<>"."
ad=Val(Mid(st1$,a,1))+Val(Mid(st2$,a,1))
If ad>10
ad=ad-10
ret=1
Else
ret=0
EndIf
result$=Str(ad)+result$
Else
result$="."+result$
EndIf
Next
If v2=0 And v1=0 ; pas de virgule on enleve les zero au debut
result$=ReplaceString(LTrim(ReplaceString(result$,"0"," "))," ","0")
Else ; on enleve les zero des deux cotes
result$=ReplaceString(LTrim(RTrim(ReplaceString(result$,"0"," ")))," ","0")
EndIf
ProcedureReturn result$
EndProcedure
bon courage pour tout implémenter personnellement je ne pense pas aller plus loin pour l'instant.
edit :correction de bug le code enlevait les zero en debut et fin de resultat meme si il n'y avais pas de virgule
050 devenais 5 au lieu de 50
Publié : mar. 06/nov./2007 22:15
par lionel_om
Si tu veux garder uniquement deux décimales, rien ne t'empeche de mémoriser ta valeur en la multipliant par 100 ou 1000 dans un entier (ou un float) et quand tu veux l'afficher, tu n'as plus qu'à diviser par la bonne valeur et afficher la valeur entière...
Lio
