(Mathe-)Aufgaben vollständig ausgeben

Anfängerfragen zum Programmieren mit PureBasic.
Tombi
Beiträge: 369
Registriert: 05.03.2008 22:05

Beitrag von Tombi »

ZeHa hat geschrieben: Vielleicht wäre es aber besser, wenn Du mal generell sagst, was Du vorhast, denn möglicherweise machst Du Dein Programm nur unnötig umständlich, und es gibt 'ne bessere Lösung. Oder probierst Du einfach nur ein bißchen rum, um die Sprache zu lernen?
Gute Idee ^^

Wie STARGÅTE schon angedeutet hat, ein "Taschenrechner".
-> Nun ja, ich versuche es ^^
Bild Bild Bild
Intel Pentium 4 630 (3 GHZ)
Benutzeravatar
ZeHa
Beiträge: 4760
Registriert: 15.09.2004 23:57
Wohnort: Friedrichshafen
Kontaktdaten:

Beitrag von ZeHa »

Ahh okay... naja da würde ich lieber gleich alle Elemente einzeln speichern und sie nur zusammen anzeigen.

Ein einfaches Beispiel: Du machst eine Struktur, die so aussieht:

Code: Alles auswählen

Structure Element
    Type.l
    Value.l
EndStructure
Und dazu noch ein paar Konstanten, z.B:

Code: Alles auswählen

#TYPE_NUMBER
#TYPE_SYMBOL

#SYMBOL_PLUS
#SYMBOL_MINUS
#SYMBOL_MULTIPLICATE
#SYMBOL_DIVIDE
Nun kannst Du einzelne Elemente per LinkedList aneinanderreihen. Zum Beispiel so:

Code: Alles auswählen

a.Element
b.Element
c.Element

a\Type = #TYPE_NUMBER
a\Value = 15

b\Type = #TYPE_SYMBOL
b\Value = #SYMBOL_PLUS

c\Type = #TYPE_NUMBER
c\Value = 7

NewList list.Element()
AddElement(list())
list() = a

AddElement(list())
list() = b

AddElement(list())
list() = c
Und diese Liste kannst Du nun per ForEach durchwandern und nach und nach das tun, was die Elemente aussagen. Also Du prüfst immer erst den Typ, und danach den Wert, und je nachdem was sie halt beinhalten kannst Du dann die Sache ausrechnen. Um den Rechenterm anzuzeigen, gehst Du ebenfalls die Liste durch, überprüfst den Typ und gibst dann entweder die Zahl oder ein Rechenzeichen aus.

Das gilt, wenn Du vorhast, einen Taschenrechner zu machen, bei dem man erst den Term zusammenbaut und hinterher auf "ausrechnen" klickt. Wenn er "live" rechnen soll, also so wie der Windows-Rechner, dann brauchst Du das aber auch nicht machen, aber ich glaube nicht, daß Du das vorhast, weil sonst würdest Du auch nicht den Gesamt-String ausgeben wollen.

PS: Tatsächlich wäre später statt einer Liste ein Baum die bessere Wahl, aber unter PB gibt's erstens keine Bäume (mußt Du selbst machen) und für den Anfang ist die Liste erstmal einfacher.
Bild     Bild

ZeHa hat bisher kein Danke erhalten.
Klicke hier, wenn Du wissen möchtest, woran ihm das vorbeigeht.
sibru
Beiträge: 265
Registriert: 15.09.2004 18:11
Wohnort: hamburg

Beitrag von sibru »

Da gibt´s irgendwo (im CodeArchiv ?) einige Sources (irgendwas mit "eval"...), hier mal ´n Source, den ich mal gefunden hab´:

Code: Alles auswählen

;Modul      Calc Version 1.1 vom 27.05.2006
;
;Funktion:  Ausrechnen eines mathematischen Ausdruckes
;           
;Aufruf:    Wert$ = Calc(Formel$)   mathem. Formel ausrechnen
;     wobei Formel$ = Ausdruck zur RechenVorschrift, kann neben konkreten Zahlen 
;                     (Komma kann sowohl . als auch , sein) folgende Zeichen ent=
;                     halten:
;                     +       Addition
;                     -       Subtraktion
;                     *       Multiplikation (auch x oder X möglich)
;                     /       Division (auch : möglich)
;                     %       Modulo (Divisions-Rest)
;                     ( )     Klammerungen
;                     !x      Fakultät (1*2*3...*x)
;                     
;                     ABS(x)  Betrag (immer positiv)
;                     SQR(x)  Quadrat-Wurzel
;                     LOG(x)  Logerithmus
;                     INV(x)  Inversion (1/x)
;                     LN(x)   natürl. Logorithmus
;                     
;                     SIN(x)  Sinus     
;                     COS(x)  Cosinus
;                     TAN(x)  Tangens 
;                     ASIN(x) Acussinus
;                     ACOS(x) Acuscosinus
;                     ATAN(x) Acustangens
;                     
;                     &       UND-Verknüpfung
;                     |       ODER-Verknüpfung
;                     >       größer
;                     <       kleiner
;                     =       gleich
;                     #MEM, #MEM1...#MEM9: Speicher-Zugriffe
;           Wurde ein fehlerhafter Ausdruck angegeben, so liefert diese Funktion
;           "ERROR", ansonsten das Ergebiss als nummerischen String (Komma ist           
;           hier .).


#EVAL_NUMS = "0123456789"  ;Die Zahlen von 0 bis 9
#EVAL_GENAUGK = 65         ;Genauigkeit für StrF() - 65 sollte eigentlich genügen, mehr bringt sowieso nichts
#EVAL_DWARF = 0.00001      ;Alles was kleiner als dieser Wert ist wird wissenschaftlich notiert
#EVAL_GIANT = 1000000      ;Alles was größer-gleich ist wird wissenschaftlich notiert
Procedure.s MyEval(expr.s) ; wird nur intern von Funktion Eval() aufgerufen
   Protected exprLeft.s, exprRight.s, exprMid.s, Result.s, exprLen.l, valLeft.f, valRight.f, i.l
   EVAL_START:
   exprLen = Len(expr)
   For i = 1 To exprLen ; In dieser Schleife schauen wir nach der ersten öffnenden Klammer
      exprMid = Mid(expr, i, 1)
      If exprMid = "("
         BracketCount = 1
         start = i
         For i = i+1 To exprLen ; wurde eine öffnende Klammer gefunden sucht diese Schleife die dazu passende schließende
            exprMid = Mid(expr, i, 1)
            If exprMid = "(" ;Sch... , noch eine Klammerebene
               BracketCount + 1
            ElseIf exprMid = ")"
               BracketCount - 1
               If BracketCount = 0 ; gefunden
                  exprLeft = Left(expr, start-1)
                  exprRight = Right(expr, exprLen - i)
                  exprMid = Mid(expr, start+1, exprLen - Len(exprLeft + exprRight) - 2)
                  exprMid = MyEval(exprMid) ; berechnen des mittleren Abschnitts (der in der Klammer)
                  If exprMid="x" : ProcedureReturn "x" : EndIf
                  expr = exprLeft + exprMid + exprRight
                  Goto EVAL_START   ;des Goto musste mal sein, ich brauch's ja sonst nie
               EndIf
            EndIf
         Next
      EndIf
   Next

   For i = exprLen To 1 Step -1
      exprMid = Mid(expr, i, 1)
      Select exprMid
      Case "="
         exprLeft  = MyEval(Left(expr, i-1))
         exprRight = MyEval(Right(expr, exprLen - i))
         If exprLeft="x" Or exprRight="x" : ProcedureReturn "x" : EndIf
         If exprLeft = exprRight : ProcedureReturn "1" : Else : ProcedureReturn "0.0" : EndIf
      Case "<"
         exprLeft  = MyEval(Left(expr, i-1))
         exprRight = MyEval(Right(expr, exprLen - i))
         If exprLeft="x" Or exprRight="x" : ProcedureReturn "x" : EndIf
         If ValF(exprLeft) < ValF(exprRight) : ProcedureReturn "1" : Else : ProcedureReturn "0.0" : EndIf
      Case ">"
         exprLeft  = MyEval(Left(expr, i-1))
         exprRight = MyEval(Right(expr, exprLen - i))
         If exprLeft="x" Or exprRight="x" : ProcedureReturn "x" : EndIf
         If ValF(exprLeft) > ValF(exprRight): ProcedureReturn "1" : Else : ProcedureReturn "0.0" : EndIf
      EndSelect
   Next

   For i = exprLen To 1 Step -1
      exprMid = Mid(expr, i, 1)
      Select exprMid
      Case "&"
         exprLeft  = MyEval(Left(expr, i-1))
         exprRight = MyEval(Right(expr, exprLen - i))
         If exprLeft="x" Or exprRight="x"
            ProcedureReturn "x"
         EndIf
         intL.l = Val(exprLeft)
         intR.l = Val(exprRight)
         intR = intR & intL
         Result = StrF(intR, #EVAL_GENAUGK)
         ProcedureReturn Result
      Case "|"
         exprLeft  = MyEval(Left(expr, i-1))
         exprRight = MyEval(Right(expr, exprLen - i))
         If exprLeft="x" Or exprRight="x"
            ProcedureReturn "x"
         EndIf
         intL.l = Val(exprLeft)
         intR.l = Val(exprRight)
         intR = intR | intL
         Result = StrF(intR, #EVAL_GENAUGK)
         ProcedureReturn Result
      EndSelect
   Next

   For i = exprLen To 1 Step -1 ; + und - Terme ausrechnen
      exprMid = Mid(expr, i, 1)
      Select exprMid
      Case "+"
         exprLeft  = Left(expr, i-1)
; statt Addition könnte es auch einfach nur ein Vorzeichen sein. Das wollen wir natürlich nicht berechnen.
         If exprLeft<>"" And FindString(#EVAL_NUMS ,Right(exprLeft, 1), 1)
            exprLeft = MyEval(exprLeft)
            exprRight = MyEval(Right(expr, exprLen - i))
            If exprLeft="x" Or exprRight="x"
               ProcedureReturn "x"
            EndIf
            Result = StrF(ValF(exprLeft) + ValF(exprRight), #EVAL_GENAUGK)
            ProcedureReturn Result
         EndIf
      Case "-"
         exprLeft  = Left(expr, i-1)
; ditto für Subtraktion
         If exprLeft<>"" And FindString(#EVAL_NUMS ,Right(exprLeft, 1), 1)
            exprLeft = MyEval(exprLeft)
            exprRight = MyEval(Right(expr, exprLen - i))
            If exprLeft="x" Or exprRight="x" : ProcedureReturn "x" : EndIf
            Result = StrF(ValF(exprLeft) - ValF(exprRight), #EVAL_GENAUGK)
            ProcedureReturn Result
         EndIf
      EndSelect
   Next
   For i = exprLen To 1 Step -1 ; Malnehmen, Teilen und Modulo (Restwertbildung)
      exprMid = Mid(expr, i, 1)
      Select exprMid
      Case "*"
         exprLeft  = MyEval(Left(expr, i-1))
         exprRight = MyEval(Right(expr, exprLen - i))
         If exprLeft="x" Or exprRight="x"
            ProcedureReturn "x"
         EndIf
         Result = StrF(ValF(exprLeft) * ValF(exprRight), #EVAL_GENAUGK)
         ProcedureReturn Result
      Case "/"
         exprLeft  = MyEval(Left(expr, i-1))
         exprRight = MyEval(Right(expr, exprLen - i))
         If exprLeft="x" Or exprRight="x"
            ProcedureReturn "x"
         EndIf
         Result = StrF(ValF(exprLeft) / ValF(exprRight), #EVAL_GENAUGK)
         ProcedureReturn Result
      Case "%"
         exprLeft  = MyEval(Left(expr, i-1))
         exprRight = MyEval(Right(expr, exprLen - i))
         If exprLeft="x" Or exprRight="x"
            ProcedureReturn "x"
         EndIf
         valLeft = ValF(exprLeft)
         valRight = ValF(exprRight)
         Result = StrF(valLeft-Int(valLeft/valRight)*valRight, #EVAL_GENAUGK)
         ProcedureReturn Result
      EndSelect
   Next

   For i = exprLen To 1 Step -1 ; Potentes Ding
      exprMid = Mid(expr, i, 1)
      If exprMid = "^"
         exprLeft  = MyEval(Left(expr, i-1))
         exprRight = MyEval(Right(expr, exprLen - i))
         If exprLeft="x" Or exprRight="x"
            ProcedureReturn "x"
         EndIf
         valLeft = ValF(exprLeft)
         valRight = ValF(exprRight)
         Result = StrF(Pow(valLeft, valRight), #EVAL_GENAUGK)
         ProcedureReturn Result
      EndIf
   Next

   exprLeft = Left(expr, 1)
   If exprLeft = "+" Or exprLeft = "-"
      vz.s = exprLeft
      expr = Right(expr, exprLen-1)
      exprLen = Len(expr)
   Else
      vz = ""
   EndIf

;und nun bis zum Schluss noch einige nützliche Funktionen
   exprLeft = Left(expr, 4)
   Select exprLeft
   Case "ASIN"
      exprRight = Right(expr, exprLen - 4)
      valRight = ValF(exprRight)
      Result = StrF(ASin(valRight), #EVAL_GENAUGK)
      ProcedureReturn vz + Result
   Case "ACOS"
      exprRight = Right(expr, exprLen - 4)
      valRight = ValF(exprRight)
      Result = StrF(ACos(valRight), #EVAL_GENAUGK)
      ProcedureReturn vz + Result
   Case "ATAN"
      exprRight = Right(expr, exprLen - 4)
      valRight = ValF(exprRight)
      Result = StrF(ATan(valRight), #EVAL_GENAUGK)
      ProcedureReturn vz + Result
   EndSelect

   exprLeft = Left(expr, 3)
   Select exprLeft
;  Select Left(expr, 3) ; Merkwürdiger Bug wenn es direkt so aufgerufen wird !!!!!!!!!!!!!!!!!!!!!!
   Case "SQR"
      exprRight = Right(expr, exprLen - 3)
      valRight = ValF(exprRight)
      If valRight <0 : ProcedureReturn "x" : EndIf
      Result = StrF(Sqr(valRight), #EVAL_GENAUGK)
      ProcedureReturn vz + Result
   Case "LOG"
      exprRight = Right(expr, exprLen - 3)
      valRight = ValF(exprRight)
      If valRight <0 : ProcedureReturn "x" : EndIf
      Result = StrF(Log10(valRight), #EVAL_GENAUGK)
      ProcedureReturn vz + Result
   Case "SIN"
      exprRight = Right(expr, exprLen - 3)
      valRight = ValF(exprRight)
      Result = StrF(Sin(valRight), #EVAL_GENAUGK)
      ProcedureReturn vz + Result
   Case "COS"
      exprRight = Right(expr, exprLen - 3)
      valRight = ValF(exprRight)
      Result = StrF(Cos(valRight), #EVAL_GENAUGK)
      ProcedureReturn vz + Result
   Case "TAN"
      exprRight = Right(expr, exprLen - 3)
      valRight = ValF(exprRight)
      Result = StrF(Tan(valRight), #EVAL_GENAUGK)
      ProcedureReturn vz + Result
   Case "ABS"
      exprRight = Right(expr, exprLen - 3)
      valRight = ValF(exprRight)
      Result = StrF(Abs(valRight), #EVAL_GENAUGK)
      ProcedureReturn vz + Result
   Case "INV"
      exprRight = Right(expr, exprLen - 3)
      valRight = ValF(exprRight)
      If valRight =0 : ProcedureReturn "x" : EndIf
      Result = StrF(1/valRight, #EVAL_GENAUGK)
      ProcedureReturn vz + Result
   EndSelect
   exprLeft = Left(expr, 2)
   Select exprLeft
   Case "LN"
      exprRight = Right(expr, exprLen - 2)
      valRight = ValF(exprRight)
      If valRight <0 : ProcedureReturn "x" : EndIf
      Result = StrF(Log(valRight), #EVAL_GENAUGK)
      ProcedureReturn vz + Result
   EndSelect
   exprLeft = Left(expr, 1)
   Select exprLeft
   Case "!"
      exprRight = Right(expr, exprLen - 1)
      valRight = ValF(exprRight)
      If Int(valRight)>=0
         valLeft = 1
         For i = 2 To Int(valRight) : valLeft * i : Next
      Else : ProcedureReturn "x" : EndIf
      Result = StrF(valLeft, #EVAL_GENAUGK)
      ProcedureReturn vz + Result
   EndSelect
   ProcedureReturn vz + StrF(ValF(expr), #EVAL_GENAUGK)
EndProcedure

Procedure.s calc(expr.s) ;Pre- und Postprocessor, eigentliches Rechnen in MyEval()
   Shared Eval_LastResult.s
   Shared Eval_Memory.s, Eval_Memory1.s, Eval_Memory2.s, Eval_Memory3.s, Eval_Memory4.s, Eval_Memory5.s, Eval_Memory6.s, Eval_Memory7.s, Eval_Memory8.s, Eval_Memory9.s
   expr = UCase(expr) ; Alles Großbuchstaben, so haben wir's beim Parsen einfacher
   expr = ReplaceString(expr, " ", "") ; Leerzeichen entfernen
   If Left(expr, 1) = "#"
      Select expr
      Case "#MEM"
         Eval_Memory = Eval_LastResult
         expr = Eval_Memory
         prependix.s = "M+ "
      Case "#MEM1"
         Eval_Memory1 = Eval_LastResult
         expr = Eval_Memory1
         prependix = "M1+"
      Case "#MEM2"
         Eval_Memory2 = Eval_LastResult
         expr = Eval_Memory2
         prependix = "M2+"
      Case "#MEM3"
         Eval_Memory3 = Eval_LastResult
         expr = Eval_Memory3
         prependix = "M3+"
      Case "#MEM4"
         Eval_Memory4 = Eval_LastResult
         expr = Eval_Memory4
         prependix = "M4+"
      Case "#MEM5"
         Eval_Memory5 = Eval_LastResult
         expr = Eval_Memory5
         prependix = "M5+"
      Case "#MEM6"
         Eval_Memory6 = Eval_LastResult
         expr = Eval_Memory6
         prependix = "M6+"
      Case "#MEM7"
         Eval_Memory7 = Eval_LastResult
         expr = Eval_Memory7
         prependix = "M7+"
      Case "#MEM8"
         Eval_Memory8 = Eval_LastResult
         expr = Eval_Memory8
         prependix = "M8+"
      Case "#MEM9"
         Eval_Memory9 = Eval_LastResult
         expr = Eval_Memory9
         prependix = "M9+"
      EndSelect
   EndIf

; Mathematische Konstanten ersetzen
   expr = ReplaceString(expr, "PI", "3.1415926535897932384626433832795") ; Kreiskonstante PI
   expr = ReplaceString(expr, "EUL", "2.7182818284590452353602874713527") ; Eulersche Zahl

; Ergebnisspeicher
   expr = ReplaceString(expr, "MEM1", Eval_Memory1)
   expr = ReplaceString(expr, "MEM2", Eval_Memory2)
   expr = ReplaceString(expr, "MEM3", Eval_Memory3)
   expr = ReplaceString(expr, "MEM4", Eval_Memory4)
   expr = ReplaceString(expr, "MEM5", Eval_Memory5)
   expr = ReplaceString(expr, "MEM6", Eval_Memory6)
   expr = ReplaceString(expr, "MEM7", Eval_Memory7)
   expr = ReplaceString(expr, "MEM8", Eval_Memory8)
   expr = ReplaceString(expr, "MEM9", Eval_Memory9)
   expr = ReplaceString(expr, "MEM", Eval_Memory)
   expr = ReplaceString(expr, "LR", Eval_LastResult) ; Das letzte Ergebnis
   expr = ReplaceString(expr, ",", ".") ; Dezimalpunkt statt Komma
   expr = ReplaceString(expr, ":", "/") ; Beide Notationen für Teilen zulassen
   expr = ReplaceString(expr, "x", "*") ; Beide Notationen für Multiplikation zulassen

; Wissenschaftliche Zahlennotation zulassen
   Repeat
      posE = FindString(expr, "E", 1)
      If posE > 0 And FindString("+-", Mid(expr, posE+1, 1), 1)
         posMant = posE - 1
         While posMant>0 And FindString(#EVAL_NUMS+".", Mid(expr, posMant, 1), 1)
            posMant - 1
         Wend
         posExp = posE + 2
         While posExp <= Len(expr) And FindString(#EVAL_NUMS+".", Mid(expr, posExp, 1), 1)
            posExp + 1
         Wend
         prt1.s = Left(expr, posMant)
         prt2.s = Mid(expr,posMant+1, posE - posMant -1)
         prt3.s = Mid(expr, posE + 1, posExp - posE -1)
         prt4.s = Right(expr, Len(expr)-posExp+1)
         expr = prt1 + "(" + prt2 + "e" + prt3 + ")" + prt4
      EndIf
   Until posE = 0
   expr = ReplaceString(expr, "e+", "*10^")
   expr = ReplaceString(expr, "e-", "*10^-")

   expr = MyEval(expr.s) ; Jetzt lassen wir richtig rechnen
   If expr = "x"
      expr = "ERROR"
   Else
      Eval_LastResult = expr ; und speichern das Ergebniss zur späteren Verwendung
; Überschüssige Nullen (und evtl. auch Dezimalpunkt) am Ende entfernen
      exprLen = Len(expr)
      While Mid(expr, exprLen, 1) = "0"
         exprLen - 1
      Wend
      expr = Left(expr, exprLen)
      If Right(expr, 1) = "."
         expr = Left(expr, exprLen-1)
      EndIf
      If expr = ""
         expr = "0"
      EndIf

; Bei kleinen und großen Zahlen die Wissenschaftliche Notation verwenden
      If expr <> "0" And Abs(ValF(expr)) < #EVAL_DWARF
;  If Abs(ValF(expr)) < #EVAL_DWARF And expr <> "0" ; auch hier ein Bug durch leicht anderen Aufruf !!!!!!!!!!!!!!
         exprLen = Len(expr)
         If Left(expr, 1) = "-"
            vz.s = "-"
            expr = Right(expr, exprLen - 3)
         Else
            vz = ""
            expr = Right(expr, exprLen - 2)
         EndIf
         exp = 1
         While Left(expr, 1) = "0"
            expr = Right(expr, Len(expr)-1)
            exp + 1
         Wend
         expr = vz + Left(expr, 1) + "." + Right(expr, Len(expr)-1) + "E-" + Str(exp)
      EndIf
      If Abs(ValF(expr)) >= #EVAL_GIANT
         exprLen = Len(expr)
         If Left(expr, 1) = "-"
            vz.s = "-"
            expr = Right(expr, exprLen - 1)
         Else
            vz = ""
         EndIf
         expr = vz + Left(expr, 1) + "." + Right(expr, Len(expr)-1) + "E+" + Str(Len(expr)-1)
      EndIf
      expr = prependix + expr
      prependix = ""
   EndIf
   ProcedureReturn expr
EndProcedure
viel Erfolg...

Sibru
Bild Bild
Antworten