Mathe. Funktionsanalyse - [Funktionen ableiten]

  • Hi Community,

    gerade bin ich dabei mir eine Funktion zu schrieben, die eine eingebene Funktion analysiert. Sprich am Ende versucht zu berechnen.

    Zu Beginn muss dazu natürlich die Funktion zerlegt werden, was ich mit dem RegEx von progandy tue und danach wird der gegebene Wert in die Funktion eingesetzt. Ich habe mal ein Beispiel, wobei die Funktion f(x)=-4x+2x+3 noch nicht viel Sinn hat. (vereinfacht => f(x)=-2x+3) Jedoch will ich damit sehen, ob die einzelenen Elemente berechnet werden.

    Skript:

    [autoit]


    #include <Array.au3>

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

    _f_analyse("f(2) = -4x+2x+3")

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

    Func _f_analyse($f)
    $f_data = StringRegExp($f,"([a-zA-Z])\(([^\)]*)\)\h*=\h*(.*)",3)
    Local $f_name = $f_data[0] ; function name
    Local $f_arg = $f_data[1] ; function argument
    Local $f_val = $f_data[2] ; function value

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

    $f_split = StringRegExp($f_val, "\h*([^()+\-\*/\^]+|[()+\-\*/\^])", 3)
    $split = StringSplit($f_split[0],"+-",0)
    If $split[0] = 1 Then ; makes sure that + or - is given for the first element
    _ArrayInsert($f_split,0,"+")
    EndIf

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

    ;~ _ArrayDisplay($f_split)

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

    Local $f_ar_val[UBound($f_split)/2][2]
    For $i = 0 To (UBound($f_split)/2)-1
    $f_ar_val[$i][0] = $f_split[$i*2]
    $f_ar_val[$i][1] = $f_split[($i*2)+1]
    Next

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

    ConsoleWrite("Function " & $f & @CRLF & "--------------")
    $str = ""
    $erg = 0
    For $i = 0 to (UBound($f_split)/2)-1
    $str &= $f_ar_val[$i][0] & StringReplace($f_ar_val[$i][1],"x","(" & $f_arg & ")")
    $erg += $f_ar_val[$i][0] & ( $f_ar_val[$i][1] * $f_arg)
    ConsoleWrite(@CRLF & "partial result - " & $i+1 & ": " & $f_ar_val[$i][0] & ( $f_ar_val[$i][1] * $f_arg))
    Next
    ConsoleWrite(@CRLF & "--------------" & @CRLF & $f_name & "(" & $f_arg & ")" & " = " & $str)
    ConsoleWrite(@CRLF & "Result: " & $erg & @CRLF)
    EndFunc

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

    Ausgegeben wird dazu jetzt:

    Code
    Function f(2) = -4x+2x+3
    --------------
    partial result - 1: -8
    partial result - 2: +4
    partial result - 3: +6
    --------------
    f(2) = -4(2)+2(2)+3
    Result: 2

    Nun geht es doch ans Eigentliche. Wie könnte ich Exponenten (-4x^2) handhaben oder z.B. Exponenten mit einer eigenen Rechnung z.B. Addition (-4x^(2x+3))?

    Ich bin da gerade auf dem Holzweg, da ich nicht weiß, wie ich die zusätzliche Info (z.b. eines Exponeten) in dem Array der einzelenen Elemente speichern soll.

    Danke bereits jetzt!

    2 Mal editiert, zuletzt von Jautois (4. März 2011 um 05:36)

  • Hi Jautois,
    so ganz ist mir ehrlich gesagt noch nicht klar, wo du im Endeffekt hin willst.
    Soll das ganze eine Art "Formelparser" werden, der ggf fehlende Klammern usw. bemängelt, oder möchtest du einfach nur einen Gleichungslöser?
    Gleichungslöser billig:

    Spoiler anzeigen
    [autoit]

    #include <String.au3>

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

    Do
    $formel_org = InputBox("Funktion y=f(x)", "Bitte die Funktion und die Variable eingeben, z.b f(4)=x^3-2x+4", "f(4)=x^2-3x+5")
    Until Not @error

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

    $a = StringSplit($formel_org, "=", 3) ;splitten vor und hinter =-Zeichen
    $x = _StringBetween($a[0], "(", ")") ;variable (argument) steht in der klammer

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

    $formel = StringReplace(StringStripWS($a[1], 8), "x", "*x") ;ggf *-Zeichen einsetzen vor das x
    $formel = StringReplace($formel, "**", "*") ;ggf doppelte *-Zeichen löschen
    If StringLeft($formel, 1) = "*" Then $formel = StringTrimLeft($formel, 1);ggf führendes *-Zeichen löschen

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

    $formel = StringReplace($formel, "x", $x[0]) ;x durch variable ersetzen

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

    $ergebnis = Execute($formel) ;ausrechnen....
    If @error Then $ergebnis = "nicht feststellbar!" ;....oder auch nicht ^^
    MsgBox(0, "Ergebnis: ", $formel_org & @CRLF & $a[0] & "=" & $ergebnis);ergebnis ausgeben

    [/autoit]
  • Hallo Jautois,
    du hast Glück das ich gerade Potenzen in Mathe habe.
    Also, angenommen du hast die Gleichung: (-4x^(2x+3))
    Dann versuch sie mit RegExp so zu Parsen, dass das Skript den Wert zwischen dem ^ und der ersten geschlossenen Klammer findet.
    Beispiel (Treffer = Rot): (-4x^(2x+3))
    Danach soll dein Skript erst das ^ löscht und dann hinter die erste geschlossene Klammer den gefundenen Inhalt anfügen,
    angeführt von einem * und in Klammern einbinden.
    Also im Kurzen:
    Ausgangsgleichung: (-4x^(2x+3)) | Nach Exponentialzeichen Suchen
    Exponentialzeichen gefunden: (-4x^(2x+3))
    Exponentialzeichen löschen: (-4x(2x+3))
    Mal Zeichen einsetzen: (-4x * (2x+3) * (2x+3))
    In Klammern einbinden: (-4x * ((2x+3) * (2x+3)))

    Wenn du sowas wie (4x^2) hast, musst du erstma RegExen ob nach dem ^ eine offene Klammer kommt,
    falls nicht, parst du (4x^2) einfach zu (4*(x*x))

    Hoffentlich konnte ich dein Problem theoretisch lösen (Kenne mich leider nicht mit RegExps aus)

    Meine Projekte:
    ClipBoard Manager (beendet)
    Gutes ClipBoard Verwaltungs Programm mit nützlichen Funktionen.

    HTML Creator (beendet)
    Nützliches Tool um schnell ein eigenes HTML Dokument zu erstellen.

  • Danke Euch!

    Ich wusste nicht wie ich mit Exponenten umgehen sollte. Habt mich aber beide auf die richtige Idee gebracht.

    Screen:
    [Blockierte Grafik: http://www7.pic-upload.de/04.03.11/9ozxtb2jpgw6.png]

    Mein Skript leitet nun Funktionen ab:

    Spoiler anzeigen
    [autoit]


    #include <Array.au3>
    #include <ButtonConstants.au3>
    #include <EditConstants.au3>
    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>

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

    Global $debug = False
    Global $timer_start, $timer_diff
    Global $formula = "f(x)=3x^4+2x^2+3x+5"

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

    $hGui = GUICreate("Ableiten - Jautois", 425, 450)
    $in_formula = GUICtrlCreateInput($formula, 8, 8, 321, 21, BitOR($GUI_SS_DEFAULT_INPUT, $ES_CENTER))
    GUICtrlSetFont(-1, 8, 800, 0, "MS Sans Serif")
    $b_derive = GUICtrlCreateButton("Ableiten", 334, 6, 81, 25)
    $e_output = GUICtrlCreateEdit("", 8, 40, 409, 361, BitOR($ES_AUTOVSCROLL, $ES_WANTRETURN, $WS_VSCROLL))
    GUICtrlSetFont(-1, 10, 800, 0, "MS Sans Serif")
    $in_arg = GUICtrlCreateInput("2", 24, 416, 137, 21, BitOR($GUI_SS_DEFAULT_INPUT,$ES_CENTER))
    GUICtrlSetFont(-1, 8, 800, 0, "MS Sans Serif")
    $b_insert = GUICtrlCreateButton("Einsetzen", 334, 414, 81, 25)
    GUICtrlCreateLabel("f(", 8, 418, 13, 20)
    GUICtrlSetFont(-1, 10, 800, 0, "MS Sans Serif")
    GUICtrlCreateLabel(") = ", 168, 418, 25, 20)
    GUICtrlSetFont(-1, 10, 800, 0, "MS Sans Serif")
    $lab_result = GUICtrlCreateLabel("", 200, 418, 121, 20)
    GUICtrlSetFont(-1, 10, 800, 0, "MS Sans Serif")
    GUISetState(@SW_SHOW, $hGui)

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

    $f_ar = _derive($formula, 5, False)

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

    ConsoleWrite(@CRLF & "Set first derivative zero to get slope: " & _f_calc_for_point("f(x)=" & $f_ar[1], 0) & @CRLF)

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

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit
    Case $b_derive
    $data = ""
    $f_ar = _derive(GUICtrlRead($in_formula), 10, True)
    $data &= "Ableitungen insgesamt: " & $f_ar[0] & @CRLF & @CRLF
    For $i = 1 To $f_ar[0]
    $data &= $i & ". Ableitung:" & @CRLF & @TAB & @TAB & $f_ar[$i] & @CRLF
    Next
    $data &= @CRLF & @CRLF & "Berechnet in: " & $timer_diff & " Sekunden"

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

    GUICtrlSetData($e_output, $data)
    Case $b_insert
    GUICtrlSetData($lab_result,_f_calc_for_point(GUICtrlRead($in_formula), GUICtrlRead($in_arg)))
    EndSwitch
    WEnd

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

    Func _f_calc_for_point($f, $point)
    $timer_start = TimerInit()
    $f_data = StringRegExp($f, "([a-zA-Z])\(([^\)]*)\)\h*=\h*(.*)", 3)
    Local $f_name = $f_data[0] ; function name
    Local $f_arg = $f_data[1] ; function argument
    Local $f_val = $f_data[2] ; function value

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

    $f_split = StringRegExp($f_val, "\h*([^()+\-\*]+|[()+\-\*])", 3)
    $split = StringSplit($f_split[0], "+-", 0)
    If $split[0] = 1 Then ; makes sure that + or - is given for the first element
    _ArrayInsert($f_split, 0, "+")
    EndIf

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

    $erg = 0
    For $i = 0 To (UBound($f_split) / 2) - 1
    $cur = StringReplace($f_split[($i * 2) + 1], $f_arg, "(" & $point & ")")
    If StringLeft($cur, 1) <> "(" Then $str_x = "*"
    $erg += Execute($f_split[$i * 2] & StringReplace($f_split[($i * 2) + 1], $f_arg, $str_x & "(" & $point & ")"))
    Next
    If $debug = True Then ConsoleWrite(@CRLF & "Result: " & $erg & @CRLF)
    $timer_diff = Round(TimerDiff($timer_start) / 1000, 4)

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

    Return $erg
    EndFunc ;==>_f_calc_for_point

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

    Func _derive($f, $count, $equation)
    $timer_start = TimerInit()
    $f_data = StringRegExp($f, "([a-zA-Z])\(([^\)]*)\)\h*=\h*(.*)", 3)
    Local $f_name = $f_data[0]
    Local $f_arg = $f_data[1]
    Local $f_val = $f_data[2]
    Local $f_ar[1]

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

    $f_split = StringRegExp($f_val, "\h*([^()+\-\*]+|[()+\-\*])", 3)
    $split = StringSplit($f_split[0], "+-", 0)
    If $split[0] = 1 Then _ArrayInsert($f_split, 0, "+")
    Local $f_new, $f_str = "'", $endl = 0
    For $j = 1 To $count
    If Execute($f_new) == 0 Then
    If $debug = True Then ConsoleWrite(@CRLF & "-> " & $f_name & $f_str & "(" & $f_arg & ") = 0" & @CRLF)
    ExitLoop
    EndIf
    ReDim $f_ar[$j]
    Local $f_r = ""
    If $j > 1 Then
    $f_split = StringRegExp($f_new, "\h*([^()+\-\*]+|[()+\-\*])", 3)
    $f_str &= "'"
    EndIf
    $f_new = ""
    For $i = 0 To (UBound($f_split) / 2) - 1
    $op = $f_split[$i * 2]
    $cur_term = $f_split[$i * 2 + 1]
    If StringInStr($cur_term, "^") Then
    If $debug = True Then ConsoleWrite(@CRLF & "-> contains exponent! - " & $cur_term & @CRLF)
    $sp_f = StringSplit($cur_term, "^", 2)
    $sp_s = StringSplit($sp_f[0], $f_arg, 2)
    If $sp_s[0] = "" Then $sp_s[0] = 1
    $new_m = $sp_s[0] * $sp_f[1] * 1
    $new_ex = $sp_f[1] - 1
    If $new_ex = 1 Then
    $new_ex = ""
    $f_new &= $op & $new_m & $f_arg
    Else
    $f_new &= $op & $new_m & $f_arg & "^" & $new_ex
    EndIf
    If $debug = True Then ConsoleWrite(@CRLF & "-> new exponent: " & $new_ex & @CRLF)
    If $debug = True Then ConsoleWrite(@CRLF & "-> new term: " & $new_m & @CRLF)
    Else
    If $debug = True Then ConsoleWrite(@CRLF & "-> doesn't contain an exponent! - " & $cur_term & @CRLF)
    If StringInStr($cur_term, $f_arg) Then
    $sp_f = StringReplace($cur_term, $f_arg, "")
    $f_r += $op & $sp_f
    Else
    #cs
    If $op = "" Then $op = "+"
    If $debug = True Then ConsoleWrite(@CRLF & "+> operator: " & $op & @CRLF)
    $f_r += $op & $cur_term
    #ce
    EndIf
    EndIf
    Next
    If $f_r > 0 Then $f_r = "+" & $f_r
    $f_new &= $f_r
    If $endl = 0 Then
    If Not StringInStr($f_new, $f_arg) Then $endl = 1
    Else
    $f_new = 0
    EndIf
    If $debug = True Then ConsoleWrite(@CRLF & "+> ints: " & $f_r & @CRLF)
    If $debug = True Then ConsoleWrite(@CRLF & "-> " & $f_name & $f_str & "(" & $f_arg & ") = " & $f_new & @CRLF)
    If $equation Then
    $f_ar[$j - 1] = $f_name & $f_str & "(" & $f_arg & ") = " & $f_new
    Else
    $f_ar[$j - 1] = $f_new
    EndIf
    Next
    _ArrayInsert($f_ar, 0, UBound($f_ar))
    $timer_diff = Round(TimerDiff($timer_start) / 1000, 4)

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

    Return $f_ar
    EndFunc ;==>_derive

    [/autoit]

    3 Mal editiert, zuletzt von Jautois (4. März 2011 um 06:36)

  • Zitat von Jautois

    Mein Skript leitet nun Funktionen ab:

    sehr schön!
    Solltest du nur die Funktionswerte der n-ten Ableitung bei komplexeren Funktionen suchen, bieten sich auch numerische Verfahren an! Weiter so! :thumbup: