• Offizieller Beitrag

    Hallo,

    Themenidee für Febraur:
    Formelauswertung.

    Es sollen also Formeln wie (3 + 45 - 2*sin(3*4)) / 2 ausgewertet werden können.
    Außerdem soll es möglich sein - z.B. für einen Funktionsplotter - Funktionswerte zu berechnen, also eine Formel wie cos(3+4/(3*x)) + 9 für verschiedene x-Werte zu berechnen.

    Funktionsrümpfe:

    [autoit]

    _evaluate($string) ; berechnet den Wert der Formel (als String), gibt den Wert zurück
    _evaluate_values($string, $start, $end, $step) ; berechnet den Wert der Formel (als String), gibt die Werte in einem nullbasierten Array zurück, $start ist der Startwert für x, $end der Endwert, $step die Schrittweite. Beispiel: _evaluate_values("cos (3 + 4)*x", 0, 10, 2)

    [/autoit]

    Zu unterstützende Funktionen: +, -, *, /, sin, cos (Groß-/Kleinschreibung egal), ^ (Potenz)
    Es muss nur der Standardwertebereich von AutoIt funktionieren.
    Die Formeln können beliebige Whitespaces (Leertasten, Tabs, Umbrüche) enthalten, die keinen Einfluss auf das Ergebnis haben dürfen.
    Die Verwendung von Eval, Execute und Konsorten ist natürlich verboten, sonst macht es ja keinen Spaß, sin, cos und exp dürfen aufgerufen werden ;).

    Es wird wie letztes Mal die Länge des Skriptes in Bytes und zusätzlich (eigenes Skript erlaubt) die Geschwindigkeit gewertet. Wer mag, kann Testdaten schreiben, sonst muss ich das irgendwann machen...

    peethebee

    p.s. noch könnt ihr auch der Aufgabe widersprechen :D.

  • Also ich find es irgendwie uach ein Bischen blöde, die beste lösung wird verboten, das ist doch bekloppt^^ Warum soll man sich mehr arbeit machen als sein muss, und wenn es dann warscheinlich auch noch besser geht ?(

    mfg. Jam00

  • Ich hab mal zufällig vorbeigeschaut, execute ist zwar verboten, aber kann man nicht jedes einzelne Zeichen per StringSplit in ein Array schreiben, und dann die Zeichen in den ungeraden Arrays benutzen um das auszurechnen? So schwer ist das doch gar nicht...

  • man könnte ja auch außenrum einen Taschenrechner mit schöner Grafik und BigInt-Unterstützung bauen :D

  • Das geht ja auch ziemlich einfach: Die Knöpfe werden gedrückt, die Zeichen werden in ein Input genommen und ausgerechnet.

    Wenn die Klammern als erstes per String-Split ermittelt werden, was ist dann?

  • Das kommt mir grad gelegen weil ich eh an sowas arbeite...

    edit: so jetz hab ich gerade erst gelesen das man execute nicht verwenden darf. Das war eig. meine Grundidee xD

    Computers are like Airconditioning. They don´t work with open Windows.

  • Hi

    muß auch sagen, daß es etwas sinnlos ist... hab aber trotzdem eine Formelauswertung geschrieben.

    Das treibende Element war, daß ich mich endlich mal mit StringRegExp auseinandersetzen wollte
    und es hat geholfen!
    Ich glaub jetzt hab ich die regular expressions endlich durchschaut :thumbup:

    Ich denke mal, ich brauche es nicht Passworten ;)
    (Außer es kommt noch ein weiterer Teilnehmer...)

    Spoiler anzeigen
    [autoit]

    Global $aFormel[5]
    $aFormel[0] = "sqrt(10^5)*log(25)"
    $aFormel[1] = "(2* sin(20)^2)/(-sqrt(120)-cos(20))"
    $aFormel[2] = "sin(20)"
    $aFormel[3] = "sin 20"
    $aFormel[4] = "10 mod 3"

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To 4
    MsgBox(0, $i, 'Formel: "' & $aFormel[$i] & '"' & @LF & @LF & "Mein Ergebnis: " & _evaluate($aFormel[$i]) & @LF & "Autoit Ergebnis: " & Execute($aFormel[$i]))
    Next

    [/autoit] [autoit][/autoit] [autoit]

    MsgBox(0, "Ergebnis", _evaluate(InputBox("Formelauswertung", "Bitte Formel eingeben:")))

    [/autoit] [autoit][/autoit] [autoit]

    Func _evaluate($sForm, $bStart = True)
    If $bStart Then
    Local $KL, $KR
    $sForm = StringStripWS($sForm, 8)
    $KL = StringRegExp($sForm, "\(", 3)
    $KR = StringRegExp($sForm, "\)", 3)
    If UBound($KL) <> UBound($KR) Then Return SetError(1, 0, "Klammer Fehler")
    EndIf
    Local $aFunc[9] = ["sin", "cos", "tan", "asin", "acos", "atan", "sqrt", "exp", "log"]
    Local $aCalc[6] = ["[\^]", "\*", "\/", "mod", "\-", "\+"]
    Local $aRet, $iRes
    While StringRegExp($sForm, "\([^\(]*?\)")
    $aRet = StringRegExp($sForm, "\([^\(]*?\)", 1)
    If Not @error Then
    $iRes = _evaluate(StringTrimRight(StringTrimLeft($aRet[0], 1), 1), False)
    $sForm = StringRegExpReplace($sForm, "\([^\(]*?\)", $iRes, 1)
    EndIf
    WEnd
    For $i In $aFunc
    While StringRegExp($sForm, "(?i)" & $i & "[0-9.]*")
    $aRet = StringRegExp($sForm, "(?i)" & $i & "[0-9.]*", 3)
    If Not @error Then
    $iRes = _Calc($i, StringTrimLeft($aRet[0], StringLen($i)))
    $sForm = StringRegExpReplace($sForm, "(?i)" & $i & "[0-9.]*", $iRes, 1)
    EndIf
    WEnd
    Next
    While StringRegExp($sForm, "[\^\+\-\*\/]|mod")
    For $i In $aCalc
    $aRet = StringRegExp($sForm, "\-?[0-9.]*" & $i & "\-?[0-9.]*", 3)
    If Not @error And $aRet[0] <> $sForm Then
    $iRes = _evaluate($aRet[0])
    $sForm = StringRegExpReplace($sForm, "\-?[0-9.]*" & $i & "\-?[0-9.]*", $iRes, 1)
    ElseIf Not @error And $aRet[0] = $sForm Then
    Return _Calc($i, $sForm)
    EndIf
    Next
    WEnd
    Return $sForm
    EndFunc ;==>_evaluate

    [/autoit] [autoit][/autoit] [autoit]

    Func _Calc($sOp, $sExpr)
    Local $aExpr
    Switch String($sOp)
    Case 'sin'
    Return Sin($sExpr)
    Case 'cos'
    Return Cos($sExpr)
    Case 'tan'
    Return Tan($sExpr)
    Case 'asin'
    Return ASin($sExpr)
    Case 'acos'
    Return ACos($sExpr)
    Case 'atan'
    Return ATan($sExpr)
    Case 'sqrt'
    Return Sqrt($sExpr)
    Case 'exp'
    Return Exp($sExpr)
    Case 'log'
    Return Log($sExpr)
    Case '[\^]'
    $aExpr = StringSplit($sExpr, "^")
    Return $aExpr[1] ^ $aExpr[2]
    Case '\+'
    $aExpr = StringSplit($sExpr, "+")
    Return $aExpr[1] + $aExpr[2]
    Case '\-'
    Local $aTmp[2] = [0, 0]
    $aExpr = StringRegExp($sExpr, "\-?[0-9.]+\-?", 3)
    If UBound($aExpr) < 2 Then $aExpr = $aTmp
    $aTmp = StringRegExp($sExpr, "\-?[0-9.]+", 1)
    If UBound($aTmp) >= 1 Then $aExpr[0] = $aTmp[0]
    Return $aExpr[0] - $aExpr[1]
    Case '\*'
    $aExpr = StringSplit($sExpr, "*")
    Return $aExpr[1] * $aExpr[2]
    Case '\/'
    $aExpr = StringSplit($sExpr, "/")
    Return $aExpr[1] / $aExpr[2]
    Case 'mod'
    $aExpr = StringSplit($sExpr, "mod")
    Return Mod($aExpr[1], $aExpr[$aExpr[0]])
    Case Else
    Return $sExpr
    EndSwitch
    EndFunc ;==>_Calc

    [/autoit]

    lgE

  • Hey, ich hab auch einen schönen Code :D

    Spoiler anzeigen
    [autoit]

    Global $aFormel[5]
    $aFormel[0] = "sqrt(10^5)*log(25)"
    $aFormel[1] = "(2* sin(20)^2)/(-sqrt(120)-cos(20))"
    $aFormel[2] = "sin(20)"
    $aFormel[3] = "sin 20"
    $aFormel[4] = "10 mod 3"

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To 4
    MsgBox(0, $i, 'Formel: "' & $aFormel[$i] & '"' & @LF & @LF & "Mein Ergebnis: " & _evaluate($aFormel[$i]) & @LF & "Autoit Ergebnis: " & Execute($aFormel[$i]))
    Next

    [/autoit] [autoit][/autoit] [autoit]

    MsgBox(0, "Ergebnis", _evaluate(InputBox("Formelauswertung", "Bitte Formel eingeben:")))

    [/autoit] [autoit][/autoit] [autoit]

    Func _evaluate($sForm, $bStart = True)
    If $bStart Then
    Local $KL, $KR
    $sForm = StringStripWS($sForm, 8)
    $KL = StringRegExp($sForm, "\(", 3)
    $KR = StringRegExp($sForm, "\)", 3)
    If UBound($KL) <> UBound($KR) Then Return SetError(1, 0, "Klammer Fehler")
    EndIf
    Local $aFunc[9] = ["sin", "cos", "tan", "asin", "acos", "atan", "sqrt", "exp", "log"]
    Local $aCalc[6] = ["[\^]", "\*", "\/", "mod", "\-", "\+"]
    Local $aRet, $iRes
    While StringRegExp($sForm, "\([^\(]*?\)")
    $aRet = StringRegExp($sForm, "\([^\(]*?\)", 1)
    If Not @error Then
    $iRes = _evaluate(StringTrimRight(StringTrimLeft($aRet[0], 1), 1), False)
    $sForm = StringRegExpReplace($sForm, "\([^\(]*?\)", $iRes, 1)
    EndIf
    WEnd
    For $i In $aFunc
    While StringRegExp($sForm, "(?i)" & $i & "[0-9.]*")
    $aRet = StringRegExp($sForm, "(?i)" & $i & "[0-9.]*", 3)
    If Not @error Then
    $iRes = _Calc($i, StringTrimLeft($aRet[0], StringLen($i)))
    $sForm = StringRegExpReplace($sForm, "(?i)" & $i & "[0-9.]*", $iRes, 1)
    EndIf
    WEnd
    Next
    While StringRegExp($sForm, "[\^\+\-\*\/]|mod")
    For $i In $aCalc
    $aRet = StringRegExp($sForm, "\-?[0-9.]*" & $i & "\-?[0-9.]*", 3)
    If Not @error And $aRet[0] <> $sForm Then
    $iRes = _evaluate($aRet[0])
    $sForm = StringRegExpReplace($sForm, "\-?[0-9.]*" & $i & "\-?[0-9.]*", $iRes, 1)
    ElseIf Not @error And $aRet[0] = $sForm Then
    Return _Calc($i, $sForm)
    EndIf
    Next
    WEnd
    Return $sForm
    EndFunc ;==>_evaluate

    [/autoit] [autoit][/autoit] [autoit]

    Func _Calc($sOp, $sExpr)
    Local $aExpr
    Switch String($sOp)
    Case 'sin'
    Return Sin($sExpr)
    Case 'cos'
    Return Cos($sExpr)
    Case 'tan'
    Return Tan($sExpr)
    Case 'asin'
    Return ASin($sExpr)
    Case 'acos'
    Return ACos($sExpr)
    Case 'atan'
    Return ATan($sExpr)
    Case 'sqrt'
    Return Sqrt($sExpr)
    Case 'exp'
    Return Exp($sExpr)
    Case 'log'
    Return Log($sExpr)
    Case '[\^]'
    $aExpr = StringSplit($sExpr, "^")
    Return $aExpr[1] ^ $aExpr[2]
    Case '\+'
    $aExpr = StringSplit($sExpr, "+")
    Return $aExpr[1] + $aExpr[2]
    Case '\-'
    Local $aTmp[2] = [0, 0]
    $aExpr = StringRegExp($sExpr, "\-?[0-9.]+\-?", 3)
    If UBound($aExpr) < 2 Then $aExpr = $aTmp
    $aTmp = StringRegExp($sExpr, "\-?[0-9.]+", 1)
    If UBound($aTmp) >= 1 Then $aExpr[0] = $aTmp[0]
    Return $aExpr[0] - $aExpr[1]
    Case '\*'
    $aExpr = StringSplit($sExpr, "*")
    Return $aExpr[1] * $aExpr[2]
    Case '\/'
    $aExpr = StringSplit($sExpr, "/")
    Return $aExpr[1] / $aExpr[2]
    Case 'mod'
    $aExpr = StringSplit($sExpr, "mod")
    Return Mod($aExpr[1], $aExpr[$aExpr[0]])
    Case Else
    Return $sExpr
    EndSwitch
    EndFunc ;==>_Calc

    [/autoit]

    Nein, war nur Spaß :)