Existe t'il une fonction pour arrondir un float?

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Mesa
Messages : 1126
Inscription : mer. 14/sept./2011 16:59

Re: Existe t'il une fonction pour arrondir un float?

Message par Mesa »

Comme ça aussi:

Code : Tout sélectionner

t.f=10.5896523
Procedure.D RoundFloat(Value.f,pLen)
ProcedureReturn (Round(value*Pow(10.0, plen),#PB_Round_Nearest)/Pow(10.0, plen))
EndProcedure
Debug RoundFloat(t,1) ;Retourne 10,6
Debug RoundFloat(t,2) ;Retourne 10,59
Debug RoundFloat(t,3) ;Retourne 10,59

M.
Avatar de l’utilisateur
GallyHC
Messages : 1708
Inscription : lun. 17/déc./2007 12:44

Re: Existe t'il une fonction pour arrondir un float?

Message par GallyHC »

bonjour,

Mesa > un truc me vient a regarder ton code, dans ton exemple tu as :

Code : Tout sélectionner

Debug RoundFloat(t,1) ;Retourne 10,6
Debug RoundFloat(t,2) ;Retourne 10,59
La je suis ok, mais pour :

Code : Tout sélectionner

Debug RoundFloat(t,3) ;Retourne 10,59
je pense qu'il manque un chiffre après la virgule non? ne devrait' il pas avoir "10.589". Enfin je n'ai pas testé, c'est juste au regard de ce qu'il est indiqué dans ton exemple.

Cordialement,
GallyHC
Configuration : Tower: Windows 10 (Processeur: i7 "x64") (Mémoire: 16Go) (GeForce GTX 760 - 2Go) - PureBasic 5.72 (x86 et x64)
Avatar de l’utilisateur
MLD
Messages : 1124
Inscription : jeu. 05/févr./2009 17:58
Localisation : Bretagne

Re: Existe t'il une fonction pour arrondir un float?

Message par MLD »

Pour le fun j'ai passé une partie de la journée a essayer. SANS résultat. 8O

Le code d'origine donné par Microsoft est le suivant: (pour VB)

Code : Tout sélectionner

Function AsymArith(ByVal X As Double, _
            Optional ByVal Factor As Double = 1) As Double
     AsymArith = Int(X * Factor + 0.5) / Factor
   End Function
ou celui-ci pour de multiple décimales

Code : Tout sélectionner


Private Function Arrondi(ByVal Nombre, ByVal Decimales)     
      Arrondi = Int(Nombre * 10 ^ Decimales + 1 / 2) / 10 ^ Decimales     
End Function
J'ai traduit ce code en PB et nada :twisted: :twisted:
Il semble qu'il a un problème avec la division en interne PB??? :(
Si quelqu'un a des idées :idea:
Avatar de l’utilisateur
kernadec
Messages : 1606
Inscription : ven. 25/avr./2008 11:14

Re: Existe t'il une fonction pour arrondir un float?

Message par kernadec »

bonsoir
idem, j'ai essayé autrement aussi
dans ce code avec debug NF dans la procédure est bien défini, mais après la division
il y a un résidu qui traine d'où vient il . :?: ..mystère

[réédit] ou alors :idea: c'est probablement Debug qui nous induit en erreur..... en interne ce doit être correct :wink:

Cordialement

Code : Tout sélectionner

;t.f=10.5956523 
t.f=10.5496523
Procedure.D RoundFloat(Value.f,pLen) 
  Protected NI,NF,Div=1,N 
  NI = Int(value * Val(LSet("1", 2 + plen , "0"))) ; multiplication avec une décimale de plus pour arrondi round()
  NF = Int(Round((NI / 10), #PB_Round_Nearest))
  Debug NF
  For N = 1 To pLen
    Div = Div * 10
  Next
  ProcedureReturn (NF / Div)
EndProcedure 
Debug RoundFloat(t,1) ;Retourne 10,5 
Debug RoundFloat(t,2) ;Retourne 10,55 
Debug RoundFloat(t,3) ;Retourne 10,550 
Avatar de l’utilisateur
kernadec
Messages : 1606
Inscription : ven. 25/avr./2008 11:14

Re: Existe t'il une fonction pour arrondir un float?

Message par kernadec »

je pense qu'on à la confirmation avec code que debug n'est pas cohérent

[réédit] avec les commentaires du test affichage :wink:

Code : Tout sélectionner

Procedure.d RoundFloat(Value.f,pLen) 
  Protected NI,NF,Div=1,N 
  NI = Int(value * Val(LSet("1", 2 + plen , "0"))) ; multiplication avec une décimale de plus pour arrondi round()
  NF = Int(Round((NI / 10), #PB_Round_Nearest))
  ;Debug "entier"
 ; Debug NF
  For N = 1 To pLen
    Div = Div * 10
  Next
     ProcedureReturn NF / Div
EndProcedure
   
   
   
t.f=10.5496523  
Debug "1er nombre test"
Debug t
Debug "--debug affiche -------------------------------"
Debug RoundFloat(t,1)           ;Retourne 10,5
Debug "--Atan du resultat affiché -------------------"
Debug ATan(RoundFloat(t,1))  
Debug "--Atan du resultat attendu---------------------"
Debug ATan(10.5)
Debug "--Atan du nombre saisi que debug affiche ------"
Debug ATan(10.5)
Debug ""
Debug "###### Ici  affichage debug non conforme "
Debug "--debug affiche pour 2 décimales ----------------"
Debug RoundFloat(t,2)         ;Retourne 10.5500000000001
Debug "Ici Atan n'est pas celui du resultat affiché ????"
Debug ATan(RoundFloat(t,2)) 
Debug "mais identique à Atan du resultat attendu !------"
Debug ATan(10.55)
Debug "--Atan du nombre saisi que debug nous affiche !---"
Debug ATan(10.5500000000001)
Debug ""
Debug "-----------------------------------------------"
Debug "###### Ici  affichage debug non conforme "
Debug "--debug affiche pour 3 décimales ----------------"
Debug RoundFloat(t,3)         ;Retourne 10.5500000000001
Debug "Ici Atan n'est pas celui du resultat affiché ????"
Debug ATan(RoundFloat(t,3)) 
Debug "mais identique à Atan du resultat attendu !------"
Debug ATan(10.550)
Debug "--Atan du nombre saisi que debug nous affiche !---"
Debug ATan(10.5500000000001)
Debug ""
Debug "-----------------------------------------------"
Debug "2ème nombre test"
Debug "------ Ici l' Affichage debug est conforme"
t.f=10.5956523 
Debug t
Debug "--debug affiche -------------------------------"
Debug RoundFloat(t,1)         ;Retourne 10,6
Debug "--Atan du resultat affiché -------------------"
Debug ATan(RoundFloat(t,1))  
Debug "--Atan du resultat attendu---------------------"
Debug ATan(10.6)
Debug "--Atan du nombre saisi que debug affiche ------"
Debug ATan(10.6)
Debug ""
Debug "--debug affiche -------------------------------"
Debug RoundFloat(t,2)         ;Retourne 10,6
Debug "--Atan du resultat affiché ????----------------"
Debug ATan(RoundFloat(t,2))  
Debug "--Atan du resultat attendu---------------------"
Debug ATan(10.6)
Debug "--Atan du nombre saisi que debug affiche ------"
Debug ATan(10.6)
Debug ""
Debug "--debug affiche -------------------------------"
Debug RoundFloat(t,3)          ;Retourne 10,596 
Debug "--Atan du resultat affiché ????----------------"
Debug ATan(RoundFloat(t,3)) 
Debug "--Atan du resultat attendu---------------------"
Debug ATan(10.596)
Debug "--Atan du nombre saisi que debug affiche ------"
Debug ATan(10.596)
Avatar de l’utilisateur
MLD
Messages : 1124
Inscription : jeu. 05/févr./2009 17:58
Localisation : Bretagne

Re: Existe t'il une fonction pour arrondir un float?

Message par MLD »

@kernadec
Oui c'est possible que ce soit débug ? Fred pourrait nous dire.
Quand j'aurai un peu de temps, je vais regarder autrement.
cordialement
Fred
Site Admin
Messages : 2805
Inscription : mer. 21/janv./2004 11:03

Re: Existe t'il une fonction pour arrondir un float?

Message par Fred »

2 choses:

1) toutes les valeurs ne sont pas representable exactement dans le format flottant. En fait tres peu le sont, les autres sont approchées. 10.57 n'est pas stockable dans le format float.

2) Utiliser les doubles pour plus de precision (c'est pareil, peu de valeurs sont representable de maniere exactes, mais leur nombre augmente beaucoup surtout avec peu de chiffre apres la virgule)

Code : Tout sélectionner

a.f = 10.57
Debug a

b.d = 10.57
Debug b
J'imagine que VB utilise les doubles par defaut, d'où la difference.
Avatar de l’utilisateur
MLD
Messages : 1124
Inscription : jeu. 05/févr./2009 17:58
Localisation : Bretagne

Re: Existe t'il une fonction pour arrondir un float?

Message par MLD »

@ Fred

Merci pour ta réponse. Bonne fin d'année pour toi et ta famille.
Ceci me rend perplexe 8O

Petite démo

Code : Tout sélectionner

a.f = 105.99 / 10
Debug a

b.d = 105.99 /10
Debug b

;

Enumeration
  #Ma_fen
  #btCalcul
  #text1
  #text2
EndEnumeration


OpenWindow(#Ma_fen,0,0,400,400,"Ma Fenêtre",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
 TextGadget(#text1,40,100, 300, 25,"",#PB_Text_Border)
 TextGadget(#text2,40,200, 300, 25,"",#PB_Text_Border)
 ButtonGadget(#btCalcul, 300,350,80,30,"Calcul")

;  Boucle générale
Repeat

     EventID = WaitWindowEvent() 
      If EventID = #PB_Event_Gadget 
      Select EventGadget() 
        Case #btCalcul 
          Select EventType()
           Case #PB_EventType_LeftClick
            a.f = 105.99 / 10
            SetGadgetText(#text1,StrF(a.f))
            b.d = 105.99 /10
            SetGadgetText(#text2,StrD(b.d))
           EndSelect 
       EndSelect 
   EndIf 
Until EventID = #PB_Event_CloseWindow 
End

Il ne reste plus qu'a construire le round_décimales.
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Existe t'il une fonction pour arrondir un float?

Message par djes »

Il faut savoir aussi que l'erreur est plus ou moins grande selon la décimale. A ta place, je convertirais tout en entier pour tes calculs d'arrondis, c'est beaucoup plus rapide. Il ne faut pas non plus perdre de vue qu'un arrondi représente une énorme perte de précision !

Comme le dit fred, pour avoir plus de précision avec les nombres à virgule, il faut utiliser le type "double" (il est là pour ça, il ne faut pas s'en priver !). Avec les doubles, l'erreur est extrêmement faible, il faut des millions (?) d'itérations pour commencer à se rendre compte de quelque chose, c'est bien plus précis qu'un horrible arrondi !

Code : Tout sélectionner

OrgFloatNumber.f=10.5689474123

NumberInteger.i = OrgFloatNumber * 100
Debug NumberInteger
NewFloatNumber.d = (NumberInteger / 100)
Debug NewFloatNumber

Avatar de l’utilisateur
MLD
Messages : 1124
Inscription : jeu. 05/févr./2009 17:58
Localisation : Bretagne

Re: Existe t'il une fonction pour arrondir un float?

Message par MLD »

@ microdevweb

voila ta solution, mais comme le dit Fred et djes passe tous tes calculs en type double

Code : Tout sélectionner

;

Enumeration
  #Ma_fen
  #btCalcul
  #text1
EndEnumeration

Procedure.D Round_decimales(nombre.d,dec.d)
 ProcedureReturn Int(nombre * Pow(10,dec) + 0.5) / Pow(10,dec)    
EndProcedure

OpenWindow(#Ma_fen,0,0,400,400,"Ma Fenêtre",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
TextGadget(#text1,40,100, 300, 25,"",#PB_Text_Border)
ButtonGadget(#btCalcul, 300,350,80,30,"Calcul")
;  Boucle générale
Repeat

     EventID = WaitWindowEvent() 
      If EventID = #PB_Event_Gadget 
      Select EventGadget() 
      
        Case #btCalcul 
          Select EventType()
           Case #PB_EventType_LeftClick
            
            SetGadgetText(#text1,StrD(Round_decimales(10.5689474123,2)))
            
           EndSelect 
       EndSelect 
   EndIf 
Until EventID = #PB_Event_CloseWindow 
End

Sur ce Bonne fin d'année a tous.
Avatar de l’utilisateur
Micoute
Messages : 2583
Inscription : dim. 02/oct./2011 16:17
Localisation : 35520 La Mézière

Re: Existe t'il une fonction pour arrondir un float?

Message par Micoute »

Moi je pense que le plus simple c'est de ne travailler qu'avec des entiers : la partie entière, dans un integer et la partie décimale, dans un autre integer.
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 6.20 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Avatar de l’utilisateur
microdevweb
Messages : 1802
Inscription : mer. 29/juin/2011 14:11
Localisation : Belgique

Re: Existe t'il une fonction pour arrondir un float?

Message par microdevweb »

Merci à tous pour vos réponses.
Windows 10 64 bits PB: 5.70 ; 5.72 LST
Work at Centre Spatial de Liège
Avatar de l’utilisateur
MLD
Messages : 1124
Inscription : jeu. 05/févr./2009 17:58
Localisation : Bretagne

Re: Existe t'il une fonction pour arrondir un float?

Message par MLD »

ou comme ceci

Code : Tout sélectionner

a.f = 10.5789474123 ;*******************
Enumeration
  #Ma_fen
  #btCalcul
  #text1
EndEnumeration

Procedure.D Round_decimales(nombre.d,dec.d)
 ProcedureReturn Int(nombre * Pow(10,dec) + 0.5) / Pow(10,dec)    
EndProcedure

OpenWindow(#Ma_fen,0,0,400,400,"Ma Fenêtre",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
TextGadget(#text1,40,100, 300, 25,"",#PB_Text_Border)
ButtonGadget(#btCalcul, 300,350,80,30,"Calcul")
;  Boucle générale
Repeat

     EventID = WaitWindowEvent() 
      If EventID = #PB_Event_Gadget 
      Select EventGadget() 
      
        Case #btCalcul 
          Select EventType()
           Case #PB_EventType_LeftClick
            
            ;SetGadgetText(#text1,StrD(Round_decimales(10.5689474123,2)))
            SetGadgetText(#text1,StrD(Round_decimales(a,2)))
           EndSelect 
       EndSelect 
   EndIf 
Until EventID = #PB_Event_CloseWindow 
End

Avatar de l’utilisateur
Micoute
Messages : 2583
Inscription : dim. 02/oct./2011 16:17
Localisation : 35520 La Mézière

Re: Existe t'il une fonction pour arrondir un float?

Message par Micoute »

Pour ne pas rester en reste:

Code : Tout sélectionner

Define.d a = 10.5789474123 ;*******************
Enumeration
  #Ma_fen
  #btCalcul
  #str0
  #str1
  #txt0
  #text1
EndEnumeration

Procedure.D Round_decimal(nombre.d, dec.d)
  ProcedureReturn Int(nombre * Pow(10, dec) + 0.5) / Pow(10, dec)
EndProcedure

OpenWindow(#Ma_fen, 0, 0, 400, 300, "Round_Decimal", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
StringGadget(#str0, 40, 50, 300, 25, StrD(a))
TextGadget(#txt0, 40, 100, 110, 25, "Nombre de décimales:")
StringGadget(#str1, 150, 95, 20, 25, "2")
TextGadget(#text1, 40, 150, 300, 25, "", #PB_Text_Border)
ButtonGadget(#btCalcul, 150, 200, 80, 30, "Calculer")
;  Boucle générale
Repeat
  
  EventID = WaitWindowEvent()
  If EventID = #PB_Event_Gadget
    Select EventGadget()
        
      Case #btCalcul
        Select EventType()
          Case #PB_EventType_LeftClick
            a = ValD(GetGadgetText(#str0))
            SetGadgetText(#text1, StrD(Round_decimal(a, Val(GetGadgetText(#str1)))))
        EndSelect
    EndSelect
  EndIf
Until EventID = #PB_Event_CloseWindow
End
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 6.20 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Mesa
Messages : 1126
Inscription : mer. 14/sept./2011 16:59

Re: Existe t'il une fonction pour arrondir un float?

Message par Mesa »

C'est tout le problème des nombres flottant.

Dans la doc de purebasic, dans la page "Variables, Types et Opérateurs", on peut lire :
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-bit) comparativement aux flottants 'simple-precision' que sont les floats (32-bit). 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.


Voir ici : http://fr.wikipedia.org/wiki/Virgule_flottante
surtout à la rubrique "Précision arbitraire" et "Précautions d'emploi".

A savoir: les nombres et les calculs avec des float sont toujours justes même si leur affichage est bizarroïde.
On ne peut pas avoir un affichage propre à moins de le programmer soi même ou d'utiliser une fonction toute prête comme la fonction printf de cette dll pour purebasic par exemple (que je n'ai pas testé): http://www.purebasic.fr/english/viewtop ... 12&t=61315

M.
Répondre