Page 1 sur 1

Priorités de calculs

Publié : mer. 21/juin/2006 2:17
par Anonyme
Salut à tous, je voudrais savoir comment m'y prendre pour
calculer une chaine de caractères du type :

S$ = " ((20-10)/2 * 5 * (50-5))+3 "

Bien entendu sans les parenthèse c'est faisable :
mais avec...

Code : Tout sélectionner

Structure Operands
  Value.f
  Prioriter.l
EndStructure


Procedure MathString(*Chaine_adresse)
  Static Buffer_Pass$
  Static CounterV.l
  Static CounterP.l
  Static Ar.f,Br.f,Fr.f
  Static OldChaine$
  
  Buffer_Pass$ = PeekS(*Chaine_adresse)
  
  StartAlgo:
  
  OldChaine$ = Buffer_Pass$
 
  Buffer_Pass$ = ReplaceString(Buffer_Pass$,Chr(47),"|")
  Buffer_Pass$ = ReplaceString(Buffer_Pass$,Chr(42),"|")
  Buffer_Pass$ = ReplaceString(Buffer_Pass$,Chr(45),"|")
  Buffer_Pass$ = ReplaceString(Buffer_Pass$,Chr(43),"|")
            
  ;Debug Buffer_Pass$
  
  For i = 1 To Len(Buffer_Pass$)
    If Mid(Buffer_Pass$,i,1)="|" : CounterV+1 : EndIf
    
      Next i 
  
      Dim Op.Operands(CounterV+1) 
      
      For i = 0 To CounterV+1
        Op(i)\Value = ValF(StringField(Buffer_Pass$,i,"|"))
        Next i
      
          
          
          Dim Pr.Operands(CounterV)  
         
          For i = 1 To Len(OldChaine$)
            If Mid(OldChaine$,i,1)="/"  : Pr(CounterP)\Prioriter = 10 : CounterP+1  :  EndIf
            If Mid(OldChaine$,i,1)="*"  : Pr(CounterP)\Prioriter = 9  : CounterP+1  :  EndIf
            If Mid(OldChaine$,i,1)="-"  : Pr(CounterP)\Prioriter = 8  : CounterP+1  :  EndIf
            If Mid(OldChaine$,i,1)="+"  : Pr(CounterP)\Prioriter = 7  : CounterP+1  :  EndIf
          Next i            
          
         
          ;;Debug
          ; For v = 1 To CounterV+1
              ; Debug Op(v)\Value
              ; If Pr(v-1)\Prioriter=10 :  Debug "/" : EndIf
              ; If Pr(v-1)\Prioriter=9  :  Debug "*" : EndIf
              ; If Pr(v-1)\Prioriter=8  :  Debug "-" : EndIf
              ; If Pr(v-1)\Prioriter=7  :  Debug "+" : EndIf
            ; Next
          
          
          
          For v = 1 To CounterV
            If Pr(v-1)\Prioriter=10
              Ar = Op(v)\Value
              Br = Op(v+1)\Value
              Fr = Ar/Br
              Buffer_Pass$ = OldChaine$
              Buffer_Pass$ = ReplaceString(Buffer_Pass$,Str(Ar)+"/"+(Str(Br)),Str(Fr))
              Dim Pr.Operands(0) : Dim Op.Operands(0) : CounterV=0 : CounterP=0 : Goto StartAlgo
             EndIf
          Next  
           
          For v = 1 To CounterV
            If Pr(v-1)\Prioriter=9
              Ar = Op(v)\Value
              Br = Op(v+1)\Value
              Fr = Ar*Br
              Buffer_Pass$ = OldChaine$
              Buffer_Pass$ = ReplaceString(Buffer_Pass$,Str(Ar)+"*"+(Str(Br)),Str(Fr))
              Dim Pr.Operands(0) : Dim Op.Operands(0) : CounterV=0 : CounterP=0 : Goto StartAlgo
            EndIf
          Next  
           
          For v = 1 To CounterV
            If Pr(v-1)\Prioriter=8
              Ar = Op(v)\Value
              Br = Op(v+1)\Value
              Fr = Ar-Br
              Buffer_Pass$ = OldChaine$
              Buffer_Pass$ = ReplaceString(Buffer_Pass$,Str(Ar)+"-"+(Str(Br)),Str(Fr))
              Dim Pr.Operands(0) : Dim Op.Operands(0) : CounterV=0 : CounterP=0 : Goto StartAlgo
            EndIf
          Next  
          
          For v = 1 To CounterV
            If Pr(v-1)\Prioriter=7
              Ar = Op(v)\Value
              Br = Op(v+1)\Value
              Fr = Ar+Br
              Buffer_Pass$ = OldChaine$
              Buffer_Pass$ = ReplaceString(Buffer_Pass$,Str(Ar)+"+"+(Str(Br)),Str(Fr))
              Dim Pr.Operands(0) : Dim Op.Operands(0) : CounterV=0 : CounterP=0 : Goto StartAlgo
            EndIf
          Next  
     
  ProcedureReturn Fr
EndProcedure

Debug MathString(@"50+100/2")


Pour ceux qui on la flème de lire le code, voici comment il procède :

- on récupère la chaine$ = 50 + 100 / 2
- on remplace tout les opérateurs par | = 50 | 100 | 2
- on compte le nombre d'opérandes
- on en deduit -1 pour les opérateurs
- on colle les opérandes & opérateurs dans des tableaux
- les opérateurs perdent leurs signes (+,-,/,*) au profit de 'priorités'
- on calcule suivant les priorités
- si il reste des opérateurs on recommence la fonction.

Etc :

1°Passe = 50 + 100 / 2
2°Passe = 50 + 50
3°Passe = 100

si quelqu'un à déjà bosser la dessus...

Ca m'enuyerais de ne pas trouver un truc fiable
car ca me sert pour mon petit interpreteur :

File:1->Splus.rar
Image

un exemple est fourni avec, ainsi que le plugin screen

@++

Publié : mer. 21/juin/2006 8:26
par Flype
l'interprétation d'expression arithmétique çà s'improvise pas.
çà s'apprends meme en cours d'algo et c'est toujours basé sur des algos récursifs sur plusieurs niveaux ( la fonction s'appellant elle meme ) sinon on s'en sort pas.
je vais te poster un code pour çà...

[EDIT]
pour ce que tu veux il faut chercher 'eval' sur les forums.
un des meilleurs est ce lien (cf forum anglais) :
http://www.dracsoft.com/zips/dracscript.zip

Publié : mer. 21/juin/2006 11:58
par Backup
tiens ! lance ça en mode debug
ça evalue la chaine expression.s
qui est egale a : Expression.s = "(2*2)+2*(3+4*(4+1))*2"
le resultat est mis dans la variable res : Debug res

:D

Code : Tout sélectionner

Procedure.s GetContent(String.s, Pos.l, First.b, Last.b) ;String = "dd(hallo)xyz", 3, '(', ')'
  Protected Content.s, *p.Byte, AnzKl.l
  *p = @String + Pos
  While *p\b
    If *p\b = First
      AnzKl.l + 1
    ElseIf *p\b = Last
      AnzKl - 1
      If AnzKl <= -1
        Break
      EndIf
    EndIf
    Content + Chr(*p\b)
    *p + 1
  Wend
  
  ProcedureReturn Content
EndProcedure

Procedure.s CalcBiExpression(ContL.s, Op.s, ContR.s) ; A+b oder A*b ...
  Protected result.s
  
  Select Op
    Case "*"
      result = Str(Val(ContL) * Val(ContR))
    Case "/"
      result = Str(Val(ContL) / Val(ContR))
    Case "+"
      result = Str(Val(ContL) + Val(ContR))
    Case "-"
      result = Str(Val(ContL) - Val(ContR))
  EndSelect
  
  
  ProcedureReturn result.s
EndProcedure


Procedure.s ProcessExpression(Exp.s)
  Protected *p.Byte, v.s, zw.l, ContL.s, ContR.s, Op.s, Cont.s
  *p = @Exp
  
  
  ;/ Search for ()
  While *p\b
    If *p\b = '('
      Cont = GetContent(Exp, *p-@Exp+1, '(', ')')
      v.s = ProcessExpression(Cont)
      Exp = ReplaceString(Exp, "("+Cont+")", v)
      *p  = @Exp
    ElseIf *p\b = ')'
      Debug "Fehler: Klammer nicht geöffnet!"
    EndIf
    *p + 1
  Wend
  
  
  ;/ Search for * bzw. /
  *p = @Exp
  While *p\b
    If *p\b = '*' Or *p\b = '/'
      zw = *p ;Zwischenspeichern
      Op = Chr(*p\b)
      ; Gehe zurück bis ein Operator kommt
      *p - 1
      ContL = ""
      While *p\b <> '*' And *p\b <> '/' And *p\b <> '+' And *p\b <> '-' And *p\b
        ContL = Chr(*p\b) + ContL
        *p - 1
      Wend
      
      *p = zw
      
      ; Gehe vorwärts bis Operator kommt
      *p + 1
      ContR = ""
      While *p\b <> '*' And *p\b <> '/' And *p\b <> '+' And *p\b <> '-' And *p\b
        ContR = ContR + Chr(*p\b)
        *p + 1
      Wend
      
      v = CalcBiExpression(ContL, Op, ContR)
      Exp = ReplaceString(Exp, ContL+Op+ContR, v)
      *p = @Exp
    EndIf
    *p + 1
  Wend
  
  ;/ Search for + bzw. -
  *p = @Exp
  While *p\b
    If *p\b = '+' Or *p\b = '-'
      zw = *p ;Zwischenspeichern
      Op = Chr(*p\b)
      ; Gehe zurück bis ein Operator kommt
      *p - 1
      ContL = ""
      While *p\b <> '*' And *p\b <> '/' And *p\b <> '+' And *p\b <> '-' And *p\b
        ContL = Chr(*p\b) + ContL
        *p - 1
      Wend
      
      *p = zw
      
      ; Gehe vorwärts bis Operator kommt
      *p + 1
      ContR = ""
      While *p\b <> '*' And *p\b <> '/' And *p\b <> '+' And *p\b <> '-' And *p\b
        ContR = ContR + Chr(*p\b)
        *p + 1
      Wend
      
      v = CalcBiExpression(ContL, Op, ContR)
      Exp = ReplaceString(Exp, ContL+Op+ContR, v)
      *p = @Exp
    EndIf
    *p + 1
  Wend
  
  
  ProcedureReturn Exp
EndProcedure




Expression.s = "(2*2)+2*(3+4*(4+1))*2"
Expression = RemoveString(Expression, " ") ;im Parser
res.s = ProcessExpression(Expression)
Debug "#############  RESULTAT  #############"
Debug res

Publié : mer. 21/juin/2006 12:30
par Anonyme
Merci à vous deux !

@Dobro, j'espèrais que tu passe ici :lol:


Sinon je pense avoir trouvé une solution de mon coté.

le principe est le suivant :

- On trouve la premiere " ( "
- On stocke sa position dans PosA.l
- On continu à parcourir la chaine

- Si on trouve " ) " on note sa position dans PosB
- On extrait PosB-PosA et on calcule, Puis on remplace (A operateur B)
par le resultat extrait

- Si on tombe sur un autre " ( " alors PosA est = à la position de "("
- etc...


@++

Publié : mer. 21/juin/2006 13:29
par Backup
Cpl.Bator a écrit :Merci à vous deux !

@Dobro, j'espèrais que tu passe ici :lol:
ya plein de code comme celui-ci sur purearea !
et sur le forum anglais ...

:D

Publié : mer. 21/juin/2006 14:35
par Anonyme
ya plein de code comme celui-ci sur purearea !
et sur le forum anglais ...
pourtant j'ai chercher :?

Publié : mer. 21/juin/2006 14:52
par Flype
eval, calc, math, expr, ...

i'm sure you can find some interesting examples :wink:

Publié : mer. 21/juin/2006 17:35
par Good07
Bonsoir Cpl.Bator.

Il y a même une fonction eval dans jaPBe. Elle existe dans l'aide externe, mais je ne me souviens pas comment on fait pour charger le programme. Depuis que je suis passé à la version 4.0 j'ai du oublier quelque chose en route. :?

Publié : mer. 21/juin/2006 18:15
par Flype
jaPBe > menu > Projet > Options du projet > Onglet 'Fichier(s) inclus' -> Cocher 'Eval'

Publié : mer. 21/juin/2006 18:26
par Good07
Merci flype. :D

Mais il semble y avoir des problèmes avec la version 4.0 de PB. Je vais voir ce que je peux faire. (J'ai des messages d'erreur sur le fichier include Math...PBI)... :(

Publié : mer. 21/juin/2006 19:05
par Flype
faut sans doute convertir le code pb3.94 en pb4.0
çà doit pas etre difficile.

ou alors tu remplace carrément le source par un nouveau code plus récent.

Publié : mer. 21/juin/2006 19:17
par Good07
Oui je pense que tu as raison, mais je n'ai pas le temps de me pencher sur le problème pour l'instant. J'ai juste essayé suite au message de Cpl.Bator car je me souvenais de m'en être servi et j'avais trouvé le code super lorsque j'essayais moi aussi de creer une fonction Eval qui existait d'ailleurs en natif dans le basic de mon Psion 5 Mx et qui manquait sur PureBasic. :(

Publié : mer. 21/juin/2006 19:22
par Flype
oui elle manque vraiment je trouve.