Unicalc Grafik - 3.0.0.3

  • Wenn man noch die Extremas (Nullstellen der 1. Ableitung) mit dazunehmen will ohne viel Aufwand zu betreiben und man ähnlich vorgehen will wie bei den Nullstellen, dann könnte man es so machen:
    Man nehme 2 aufeinanderfolgende Punkte und stelle fest ob der Anstieg der Kurve zwischen ihnen positiv oder negativ ist (Einfach die beiden Werte subtrahieren).
    Wenn bei x=1 z.B. y=2 ist und bei x=2 y=1 dann ist der Anstieg negativ.
    Nun betrachte man den nächsten darauffolgenden Punkt.
    Also wieder ins Beispiel: Wenn bei x=3 y>1 dann muss zwischen x=2 und x=3 ein Extrema sein. (wenn die Funktion stetig ist).
    Genauer gesagt ein Minimum.
    Für die genaue Lokalisation kann man dann die numerischen Lösungsverfahren entsprechend anwenden.

    Bei den Wendepunkten wird es dann noch ekliger weil diese dann die Nullstelle der 2. Ableitung darstellen.
    Zwar könnte man dann hier 4 aufeinanderfolgende Punkte entsprechend auswerten aber dann muss man sich schon fragen ob das noch effektiv ist.
    Hier würde ich daher eher auf eine numerische Differentation ausweichen und diese dann auswerten.

    Aber wie gesagt: Für 10. Klasse ist das schonmal weit über dem Horizont was du hier ablieferst und von daher sollte es auch keinen Druck von außen und noch viel weniger von dir selbst geben unbedingt soviel wie möglich zu implementieren.
    Versuch es doch erstmal mit der numerischen Lösung einer Nullstelle (was schon über deinem derzeitigen Bildungsniveau liegen sollte).
    Wenn du das hast und weiter machen willst dann implementiere die Sache mit der Nullstellensuche über den gesamten Definitionsbereich usw.
    Du hast Zeit - und du bist jetzt schon verdammt weit.

  • Naja der Definitonsbereich liegt bei +/- unendlich :D
    Die X-Achse nach Vorzeichenwechsel abzuklappern ist aber trotzdem eine gute Idee, gerade bei Nullstellen, die sich nicht innerhalb der Grafik befinden.

    Hoch- / Tiefpunkte schau ich mal übers WE.
    Wendepunkte ähm naja wenns es da keine geniale Vereinfachung gibts brauchen wir dazu nen Profi - UEZ oder Andy würde ich das zutrauen 8)

  • Na +- unendlich interessiert hier ja erstmal nicht sondern lediglich der Ausschnitt der auch geplottet wird.
    Oder hab ich das etwas falsch verstanden?
    Weil mit numerischen Lösungen wird man nie alle Lösungen finden.
    Halt nur in einem gewissen Bereich.
    Ansonsten muss man es algebraisch lösen - aber das ist, gerade in Programmen umgesetzt, absolut nichts mehr für Nicht-Mathematiker.

    €dit: Oder meintest du weil die streng mathematische Definition von "Definitionsbereich" nichts mit unserem Plottingbereich zu tun hat?
    Weil wenn kannst du das nicht so einfach sagen - ist ja funktionsabhängig ;)

  • Nee genau so sehe ich das auch.

    Druck aufbauen möchte ich natürlich nicht. Kannst auch warten bis ihr das Thema in Mathe durchgenommen habt und dann entscheiden ob du es einbauen willst.

    edit \ Ich meinte, dass die möglichen Funktionen in Unicalc auch Nullstellen/Extremstellen außerhalb des Plottingbereichs haben können (im Bereich +/- unendlich).

    3 Mal editiert, zuletzt von nuts (13. Januar 2010 um 18:18)

  • Ja wenn es aber außerhalb des Plottingbereiches gelöst werden soll muss ja wieder ein extra übergeordneter Bereich festgelegt werden.
    Sonst lässt es sich nicht numerisch lösen.

    Btw. -> Gibts im Lehrplan eigentlich numerische Lösungsmethoden?
    Weil kann mich nicht erinnern sowas in der Schule mal gehabt zu haben.
    Kurvendiskussion ja - aber numerisch lösen?

  • Klaro, den Bereich muss man definieren.

    z.B. man vermutet eine Nullstelle irgendwo x >0 und schickt das Skript 1000 "Einheiten" nach "rechts"
    -> Nullstelle gefunden (y|x)
    oder
    -> keine Nullstelle gefunden - Suchbereich erweitern?

    Numerische Lösungsmethoden waren bei uns in der Schule manchmal die Einleitung ins Thema.

  • Also Druck mache ich mir sowieso nicht. Ich mach das weil es mir Spaß macht, und am meisten Spaß machen mir daran halt die Grafischen Aspekte nicht die mathematischen (auch wenn mir mathe spaß macht ^^ ). Es steckt ja auch nicht sonderlich viel mathe in Unicalc drin, nur Flächenberechnung, Tangenten und die Darstellung von den Gleichungen.

    Nur noch mal zum klarstellen:
    Numerisch heißt was?
    Sozusagen durch "Ausprobieren" bzw. "Die x-Achse langehen" ?

    Nullstellen würde ich vielleicht hinkriegen durch "x-Achse langehen und nach Wertänderungen schauen", bei den Extremas wäre das vielleicht auch anwendbar. Das wäre ja schonmal was.
    Bin ich bis jetzt mitgekommen ?

    mfg
    Ludwig

  • http://de.wikipedia.org/wiki/Numerische_Mathematik

    Bist mitgekommen würde ich sagen. ;)

    edit \ Hab die Nullstellen mal etwas ausgearbeitet. Bei den Rückgabewerten habe ich etwas gepfuscht :D

    Spoiler anzeigen
    [autoit]


    #include <Array.au3>
    HotKeySet("{ESC}", "Terminate") ; press ESC to emergency-exit

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

    Global $expression = InputBox("Enter Function", "E.g. x^2-16", "x^2-16") ; make sure you use * to multiply
    If @error Then Exit
    ; auf die Konforme Funktionsübergabe kann man ja in Unicalc selbst achten
    ; Y=0 in die eingegeben Funktion von Unicalc einsetzen und übergeben

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

    $array =_ReturnZero($expression, -10, 10)
    _ArrayDisplay($array, "X- Werte der Nullstellen")

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

    Func Terminate()
    Exit
    EndFunc ;==>Terminate

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

    Func _ReturnZero($expr, $startpoint, $endpoint, $dez = 0.01)
    ;expr: Funktion
    ;§leftbound = Linke Grenze
    ;$rightbound = Rechte Grenze
    ;$dez = Suchintervall -> je kleiner je mehr loops werden benötigt -> Risiko 2er Nullstellen im Intervall wird jedoch verkleinert
    ;return: Array mit den x-Werten der Nullstellen im angegebenen Bereich
    ;@error; Kein Treffer im angegebenen Bereich
    Local $calc, $temp, $match = "", $asplit, $sreturn
    For $x = $startpoint To $endpoint Step $dez
    $calc = Execute(StringReplace($expr, "x", $x))
    If $calc > 0 And $temp < 0 Then
    $match &= String($x) & "|"
    $temp = $calc
    ElseIf $calc < 0 And $temp > 0 Then
    $match &= String($x) & "|"
    $temp = $calc
    Else
    $temp = $calc
    EndIf
    Next
    If $match = "" Then Return SetError(0)
    $asplit = StringSplit($match, "|")
    _ArrayDisplay($asplit, "Return Guess") ;zum überprüfen
    Local $areturn[$asplit[0]-1]
    For $i = 1 To $asplit[0] - 1
    $t = _CalcZero($expression, $asplit[$i])
    if not @error then $areturn[$i-1] = $t
    Next
    Return $areturn
    EndFunc ;==>_Check

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

    Func _CalcZero($expr, $guess)
    Local $x_guesses_array[2] ; Zum Vergleich der Ergebnisse, bei entsprechender Genauigkeit wird abgebrochen
    Local $x_guess = Number($guess)
    Local $c = 0
    local $zero
    While 1
    $x_guess = $x_guess - (_Fx($expression, $x_guess) / _SlopeOfTangent($expression, $x_guess)) ;Newton
    $c += 1
    If IsInt($c / 1000) And Not IsInt($c / 2000) Then
    $x_guesses_array[0] = $x_guess
    $x_guesses_array[1] = 0
    EndIf
    If IsInt($c / 2000) Then
    ;Genauigkeit des Ergebnis wird überprüft (alle 2000 loops)
    $x_guesses_array[1] = $x_guess
    If Abs($x_guesses_array[1] - $x_guesses_array[0]) < 0.001 Then ExitLoop
    EndIf
    If $c >= 10000 Then
    $zero=_CheckZeroZero($expr)
    if $zero then
    Return 0 ;geht durch 0|0
    else
    Return SetError(0) ;kein match
    endif
    EndIf
    WEnd
    Return $x_guess
    EndFunc ;==>_CalcZero

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

    Func _SlopeOfTangent($expr, $at_point, $var = "x", $places = 4)
    Local $dx = 0.00000001
    Local $x = $at_point
    Local $y = $x + $dx
    Local $slope = Execute(StringReplace($expr, $var, "$y")) - Execute(StringReplace($expr, $var, "$x"))
    Return Round($slope / $dx, $places)
    EndFunc ;==>_SlopeOfTangent

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

    Func _Fx($expr, $at_point)
    Return Execute(StringReplace($expr, "x", "$at_point"))
    EndFunc ;==>_Fx

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

    func _CheckZeroZero($expr)
    if Execute(StringReplace($expr, "x", 0)) = 0 then
    Return true
    else
    Return false
    endif
    endfunc

    [/autoit]

    2 Mal editiert, zuletzt von nuts (14. Januar 2010 um 13:01)

  • Oh ... ich hatte garnicht gesehen, dass du auch schon ein Nullstellen Beispiel gemacht hast ...
    Ich hab jetzt nämlich auch noch eins gemacht, aber ziemlich anders. Ich geh einfach die x-Achse lang und wenn ein Vorzeichenwechsel ist, dann geht er noch mal genauer in den Bereich und dann nochmal ... rekursiv halt.

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>
    $GrafikSeperator = "¤"
    $Pi = 3.141
    $Array = StringSplit(_GR_Nullstellen(_FormatString("sin(x)"), -5, 5), $GrafikSeperator, 1)
    _ArrayDisplay($Array)

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

    ; #FUNCTION# ;===============================================================================
    ;
    ; Name...........: _GR_Nullstellen
    ; Description ...: Liefert alle Nullstellen zwischen $_zG_XStart und $_zG_XEnde
    ; Syntax.........: _GR_Nullstellen($_zG_Funktion, $_zG_XStart, $_zG_XEnde)
    ; Return values .: String mit allen gefundenen Nullstellen (mit $GrafikSeperator unterteilt)
    ; Author ........: Ludwig Waffenschmidt
    ;
    ;============================================================================================
    Func _GR_Nullstellen($_zG_Funktion, $_zG_XStart, $_zG_XEnde, $iRekursion = 0)
    Local $_zG_LastVorzeichen, $_zG_Nullstellen, $_zG_Vorzeichen
    If $iRekursion > 5 Then Return Round(($_zG_XStart + $_zG_XEnde) / 2, 5) ;Rekursion einschränken und Mittelwert zurückgeben
    $_zG_LastX = $_zG_XStart
    $_zG_Step = (Abs($_zG_XStart) + Abs($_zG_XEnde)) / 1000
    For $_zG_X = $_zG_XStart To $_zG_XEnde Step + $_zG_Step

    $_zG_FunktionMitX = $_zG_Funktion
    $_zG_FunktionMitX = StringReplace($_zG_FunktionMitX, "exp", "~1¦~~î~?~•~~")
    $_zG_FunktionMitX = StringReplace($_zG_FunktionMitX, "x", "$_zG_X")
    $_zG_FunktionMitX = StringReplace($_zG_FunktionMitX, "~1¦~~î~?~•~~", "exp")

    $_zG_Y = Round(Execute($_zG_FunktionMitX), 2)

    If $_zG_Y = 0 Then
    $_zG_Vorzeichen = ""

    ;~ ConsoleWrite($iRekursion & "|" & $_zG_X & "|" & $_zG_Y & "|" & $_zG_Vorzeichen & @CRLF)

    If $iRekursion <> 0 Then Return Round($_zG_X, 5)
    ContinueLoop
    ElseIf $_zG_Y > 0 Then
    $_zG_Vorzeichen = "+"
    If $_zG_LastVorzeichen = "" Then $_zG_LastVorzeichen = $_zG_Vorzeichen
    ElseIf $_zG_Y < 0 Then
    $_zG_Vorzeichen = "-"
    If $_zG_LastVorzeichen = "" Then $_zG_LastVorzeichen = $_zG_Vorzeichen
    EndIf

    ;~ ConsoleWrite($iRekursion & "|" & $_zG_X & "|" & $_zG_Y & "|" & $_zG_Vorzeichen & @CRLF)

    If $_zG_LastVorzeichen <> "" Then
    If $_zG_LastVorzeichen <> $_zG_Vorzeichen Then
    $_zG_LastVorzeichen = $_zG_Vorzeichen
    $_zG_Nullstellen &= $GrafikSeperator & _GR_Nullstellen($_zG_Funktion, $_zG_LastX, $_zG_X, $iRekursion + 1)
    EndIf
    EndIf
    $_zG_LastX = $_zG_X
    Next
    Return StringTrimLeft($_zG_Nullstellen, 1)
    EndFunc

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

    Func _FormatString($sString)
    $sString = StringReplace($sString, ",", ".")
    $sString = StringReplace($sString, "fact(", "_Fact(")

    $sString = StringReplace($sString, "log(", "Deklog(")

    $sString = StringReplace($sString, "sin(" , "~1¦~~î~?~•~~")
    $sString = StringReplace($sString, "In(", "Log(")
    $sString = StringReplace($sString, "~1¦~~î~?~•~~", "sin(")

    $sString = StringReplace($sString, "sqrt(" , "~1¦~~î~?~•~~")
    $sString = StringReplace($sString, "sqr(", "sqrt(")
    $sString = StringReplace($sString, "~1¦~~î~?~•~~", "sqrt(")

    $sString = StringReplace($sString, "²", "^2")
    $sString = StringReplace($sString, "³", "^3")

    $sString = StringReplace($sString, "Cosh(", "_Cosh(")
    $sString = StringReplace($sString, "Tanh(", "_Tanh(")
    $sString = StringReplace($sString, "Sinh(", "_Sinh(")

    $sString = StringReplace($sString, "gauss(", "int(")
    $sString = StringReplace($sString, "ceil(", "ceiling(")

    For $i = 1 To 9 ;Damit man auch z.B "2x" schreiben kann (--> "2*x")
    $sString = StringReplace($sString, $i & "x", $i & "*x")
    $sString = StringReplace($sString, $i & "Pi", $i & "*Pi")
    Next

    $sString = StringReplace($sString, "Pi", $Pi)

    Return $sString
    EndFunc

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

    Func Deklog($_zahl)
    Return Log($_zahl) / Log(10)
    EndFunc ;==>Deklog

    [/autoit]

    Habs halt gleich so gemacht, dass ich es ohne Probleme direkt in den Quellcode von Unicalc Grafik einbauen kann.

    mfg
    Ludwig

  • Viele Wege führen nach Rom.
    So genau ist das aber nicht oder? ?(
    z.B. x^3
    \edit: Der Ursprungspunkt ist auch fies, hab mich auch drumrumgemogelt 8)
    Bei einer doppelte Nullstelle (z.B. x^2) liefern beide Ansätze noch kein Ergebnis.

    P.S: Pi = 4 * ATan(1)

    Einmal editiert, zuletzt von nuts (14. Januar 2010 um 21:18)

  • Deine Variante ist DEUTLICH besser. Ich hab sie mal umgeschrieben und auf den Quellcode von Unicalc angepasst:

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>
    HotKeySet("{ESC}", "Terminate") ; press ESC to emergency-exit

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

    Global $_zG_Funktionession = InputBox("Enter Function", "E.g. x^2-16", "x^2-16")
    If @error Then Exit

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

    $array = _GR_Nullstellen($_zG_Funktionession, -10, 10)
    _ArrayDisplay($array)

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

    Func Terminate()
    Exit
    EndFunc ;==>Terminate

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

    ; #FUNCTION# ;===============================================================================
    ;
    ; Name...........: _GR_Nullstellen
    ; Description ...: Liefert alle Nullstellen zwischen $_zG_XStart und $_zG_XEnde
    ; Syntax.........: _GR_Nullstellen($_zG_Funktion, $_zG_XStart, $_zG_XEnde)
    ; Return values .: Array mit allen gefundenen Nullstellen
    ; Author ........: nuts
    ; Modified.......: Ludwig Waffenschmidt
    ;
    ;============================================================================================
    Func _GR_Nullstellen($_zG_Funktion, $_zG_XStart, $_zG_XEnde)
    Local $_zG_LastY, $_zG_Guess = "", $_zG_Guess, $_zG_GuessArray[2]
    For $_zG_X = $_zG_XStart To $_zG_XEnde Step 0.01

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

    $_zG_Y = _Fx($_zG_Funktion, $_zG_X)

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

    If ($_zG_Y > 0 And $_zG_LastY < 0) Or ($_zG_Y < 0 And $_zG_LastY > 0) Then

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

    $_zG_Count = 0
    While 1
    $_zG_X = $_zG_X - (_Fx($_zG_Funktion, $_zG_X) / Round((_Fx($_zG_Funktion, $_zG_X + 0.00000001) - _Fx($_zG_Funktion, $_zG_X)) / 0.00000001, 4)) ;Newton
    $_zG_Count += 1
    If IsInt($_zG_Count / 500) And Not IsInt($_zG_Count / 1000) Then
    $_zG_GuessArray[0] = $_zG_X
    $_zG_GuessArray[1] = 0
    EndIf
    If IsInt($_zG_Count / 1000) Then
    ;Genauigkeit des Ergebnis wird überprüft (alle 2000 loops)
    $_zG_GuessArray[1] = $_zG_X
    If Abs($_zG_GuessArray[1] - $_zG_GuessArray[0]) < 0.001 Then ExitLoop
    EndIf
    If $_zG_Count >= 10000 Then
    If _Fx($_zG_Funktion, 0) = 0 Then
    Return 0 ;geht durch 0|0
    Else
    Return SetError(0) ;kein match
    EndIf
    EndIf
    WEnd

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

    $_zG_Guess &= $_zG_X & "|"
    $_zG_LastY = $_zG_Y
    Else
    $_zG_LastY = $_zG_Y
    EndIf
    Next
    Return StringSplit(StringTrimRight($_zG_Guess, 1), "|")
    EndFunc ;==>_GR_Nullstellen

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

    Func _Fx($_zG_Funktion, $_zG_X)
    $_zG_FunktionMitX = $_zG_Funktion
    $_zG_FunktionMitX = StringReplace($_zG_FunktionMitX, "exp", "~1¦~~î~?~•~~")
    $_zG_FunktionMitX = StringReplace($_zG_FunktionMitX, "x", "$_zG_X")
    $_zG_FunktionMitX = StringReplace($_zG_FunktionMitX, "~1¦~~î~?~•~~", "exp")

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

    Return Execute($_zG_FunktionMitX)
    EndFunc ;==>_Fx

    [/autoit]

    PS: Ich hab das Pi nur so eben so definiert für die FormatString, in Unicalc ist das besser definiert ;)

    //Edit: Unicalc Grafik 3.0.0.2 ist raus! Jetzt mit den Nullstellen! Siehe 1. Post

    2 Mal editiert, zuletzt von Ludwig (14. Januar 2010 um 22:03)

  • Hab dir mal ein paar Funktionen gebastelt welche du vielleicht verwenden kannst.
    Hab sie so gestaltet das der Einfluss des Rundungsfehlers, welcher bei Binärdarstellung von Gleitkommazahlen existiert, möglichst gering wird und so die Ergebnisse möglichst genau.
    Bei der Nullstellensuche hab ich die Näherungsmethode ausgelagert, so dass man relativ einfach die Methode wechseln kann.
    Erstmal hab ich dir dafür die Bisektionsmethode implementiert.
    Zwar konvergieren Verfahren wie das Newtonverfahren deutlich schneller aber bei ihnen besteht die Gefahr sich in einer Endlosschleife zu verfangen wenn die Grenzen ungünstig liegen.
    Als nächste Übung könnte man daher mal statt dem Newton-Verfahren den Regula-Falsi -Algorithmus zu implementieren welcher auf dem Sekantenverfahren basiert und im Gegensatz zum Newton-Verfahren immer konvergiert.

    Also hoffe du kannst etwas davon gebrauchen:

    Spoiler anzeigen
    [autoit]

    Global Const $FLT_EPSILON = _GET_FLT_EPSILON()

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

    ;----------------------------Funktionswerte & Ableitungen-----------------------------
    Global $Fx = "cos(x)"
    Global $x = 2

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

    ConsoleWrite("Funktion = " & $Fx & @CRLF & _
    "x = " & $x & @CRLF & _
    "F(x) = " & _Fx($Fx, $x) & @CRLF & _
    "F'(x) = " & _Abl1($Fx, $x) & @CRLF & _
    "F''(x) = " & _Abl2($Fx, $x) & @CRLF & @CRLF)
    ;-------------------------------------------------------------------------------------

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

    ;----------------------------Nullstellensuche-----------------------------------------
    Global $a = -10 ; linke Grenze
    Global $b = 10 ; rechte Grenze

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

    ConsoleWrite("------------------Nullstellensuche---------------------" & @CRLF & _
    "Funktion: " & $Fx & @CRLF & _
    "Intervall: " & $a & ", " & $b & @CRLF & @CRLF & _
    " x" & @TAB & @TAB & " F(x)" & @TAB & " Iterationen" & @CRLF)
    _GetRoots($Fx, $a, $b, 2 ^ (-12))
    ConsoleWrite("-------------------------------------------------------" & @CRLF)
    ;-------------------------------------------------------------------------------------

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

    ;-----------------------------lokale Extrema------------------------------------------
    ConsoleWrite("------------------lokale Extrema-----------------------" & @CRLF & _
    "Funktion: " & $Fx & @CRLF & _
    "Intervall: " & $a & ", " & $b & @CRLF & @CRLF & _
    " x" & @TAB & @TAB & " F(x)" & @TAB & " Iterationen" & @CRLF)
    _GetExtremas($Fx, $a, $b, 2 ^ (-12))
    ConsoleWrite("-------------------------------------------------------" & @CRLF)
    ;-------------------------------------------------------------------------------------

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

    Func _Fx($_zG_Funktion, $_zG_X)
    $_zG_FunktionMitX = $_zG_Funktion
    $_zG_FunktionMitX = StringReplace($_zG_FunktionMitX, "exp", "~1¦~~î~?~•~~")
    $_zG_FunktionMitX = StringReplace($_zG_FunktionMitX, "x", "$_zG_X")
    $_zG_FunktionMitX = StringReplace($_zG_FunktionMitX, "~1¦~~î~?~•~~", "exp")

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

    Return Execute($_zG_FunktionMitX)
    EndFunc ;==>_Fx

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

    ; #FUNCTION#=================================================================================
    ; Name...........: _GetExtremas
    ; Description ...: Findet alle Bereiche eines Intervalls in denen ein Extrema vorkommt
    ; Voraussetzung: h < minimalste Abstand 2er Extremas
    ; Syntax.........: _GetExtremas($F_X, $a, $b, $h)
    ; Parameters.....: $F_X: String einer Funktionsdefinition abhängig von x
    ; $a: linke Suchbereichsgrenze
    ; $b: rechte Suchbereichsgrenze
    ; $h: Schrittweite der Suchintervalle
    ; Return values..: True: Erfolgreich
    ; False: Fehler
    ; @error= 1: a>=b
    ; Requirements...: Funktion float _Fx( string F(x), float x )
    ; Author ........: AspirinJunkie
    ;============================================================================================
    Func _GetExtremas($F_X, $a, $b, $h)
    If $a >= $b Then Return SetError(1, 0, False)

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

    Local $x = $a, $y = $a + $h, $z = $a + 2 * $h
    Local $Fx = _Fx($F_X, $x), $Fy = _Fx($F_X, $y), $Fz = _Fx($F_X, $z)
    Local $fExtr, $dIterations

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

    While $z < $b
    Select
    Case $Fy - $Fx > 0
    If $Fz < $Fy Then
    $fExtr = _Lok_Extr($F_X, $x, $z, "Max")
    $dIterations = @extended
    ConsoleWrite(StringFormat("Max: %f\t%.2e\t%d", $fExtr, _Fx($F_X, $fExtr), $dIterations) & @CRLF)
    EndIf
    Case $Fy - $Fx < 0
    If $Fz > $Fy Then
    $fExtr = _Lok_Extr($F_X, $x, $z, "Min")
    $dIterations = @extended
    ConsoleWrite(StringFormat("Min: %f\t%.2e\t%d", $fExtr, _Fx($F_X, $fExtr), $dIterations) & @CRLF)
    EndIf
    EndSelect
    $x = $y
    $y = $z
    $z += $h

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

    $Fx = $Fy
    $Fy = $Fz
    $Fz = _Fx($F_X, $z)
    WEnd

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

    Return True
    EndFunc ;==>_GetExtremas

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

    ; #FUNCTION#=================================================================================
    ; Name...........: _GetRoots
    ; Description ...: Findet alle Bereiche eines Intervalls in denen eine Nullstelle vorkommt
    ; Voraussetzung: h < minimalste Abstand 2er Nullstellen und
    ; Nullstelle != Extrema der Funktion
    ; Syntax.........: _GetRoots($F_X, $a, $b, $h)
    ; Parameters.....: $F_X: String einer Funktionsdefinition abhängig von x
    ; $a: linke Suchbereichsgrenze
    ; $b: rechte Suchbereichsgrenze
    ; $h: Schrittweite der Suchintervalle
    ; Return values..: True: Erfolgreich
    ; False: Fehler
    ; @error= 1: a>=b
    ; Requirements...: Funktion float _Fx( string F(x), float x )
    ; Author ........: AspirinJunkie
    ;============================================================================================
    Func _GetRoots($F_X, $a, $b, $h)
    If $a >= $b Then Return SetError(1, 0, False)

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

    Local $l = $a, $r = $a + $h
    Local $Fl = _Fx($F_X, $l), $Fr
    Local $fRoot, $dIterations

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

    While $r < $b
    $Fr = _Fx($F_X, $r)

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

    If ($Fr = 0) Then
    ConsoleWrite(StringFormat("%f\t %d\t\t%d", $r, 0, 0) & @CRLF)
    ElseIf ($Fl < 0 And $Fr >= 0) Or ($Fl >= 0 And $Fr < 0) Then
    $fRoot = _Bisektion($F_X, $l, $r)
    $dIterations = @extended
    ConsoleWrite(StringFormat("%f\t%.2e\t%d", $fRoot, _Fx($F_X, $fRoot), $dIterations) & @CRLF)
    EndIf

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

    $Fl = $Fr
    $l = $r
    $r += $h
    WEnd

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

    Return True
    EndFunc ;==>_GetRoots

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

    ; #FUNCTION#=================================================================================
    ; Name...........: _Lok_Extr
    ; Description ...: Berechnet die lokalen Extrema in einem Intervall numerisch
    ; Methode: Eigener Algorithmus zur stetigen Intervallverkleinerung
    ; Syntax.........: _Lok_Extr($F_X, $Start, $End, $sTyp)
    ; Return values .: X-Wert des lokalen Extremas
    ; @Extended = Anzahl Iterationen
    ; bei Fehler: @error = 1 : $Start >= $End
    ; = 2 : ungültiger Wert für $sTyp
    ; Parameters.....: $F_X: String einer Funktionsdefinition abhängig von x
    ; $Start: linke Suchbereichsgrenze
    ; $End: rechte Suchbereichsgrenze
    ; $sTyp: String "Max" oder "Min"
    ; Requirements ..: Funktion float _Fx( string F(x), float x )
    ; Global $FLT_EPSILON = float
    ; Author ........: AspirinJunkie
    ;============================================================================================
    Func _Lok_Extr($F_X, $Start, $End, $sTyp)
    If $Start >= $End Then Return SetError(1, 0, False)

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

    Local $n = 0
    Local $dx = ($Start - $End) / 3
    Local $a = $Start, $b = $Start + $dx, $c = $End - $dx, $d = $End
    Local $Fa = _Fx($F_X, $a), $Fb = _Fx($F_X, $b), $Fc = _Fx($F_X, $c), $Fd = _Fx($F_X, $d)

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

    If Not ($sTyp = "Max" Or $sTyp = "Min") Then Return SetError(2, 0, 0)

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

    Switch $sTyp

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

    Case "Max"
    While True
    $n += 1

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

    If Abs($dx) < $FLT_EPSILON ^ (1 / 1.1) Then ExitLoop

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

    If ($Fb - $Fa >= 0 And $Fc - $Fb >= 0) Or ($Fc - $Fb > 0 And $Fd - $Fc > 0) Then
    $a = $b
    $Fa = $Fb
    ElseIf ($Fc - $Fb < 0 And $Fd - $Fc <= 0) Or ($Fb - $Fa <= 0 And $Fc - $Fb <= 0) Then
    $d = $c
    $Fd = $Fc
    EndIf

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

    $dx = ($d - $a) / 3
    $b = $a + $dx
    $c = $d - $dx
    WEnd
    Case "Min"
    While True
    $n += 1
    If Abs($dx) < $FLT_EPSILON ^ (1 / 1.1) Then ExitLoop

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

    If ($Fb - $Fa <= 0 And $Fc - $Fb <= 0) Or ($Fc - $Fb < 0 And $Fd - $Fc < 0) Then
    $a = $b
    $Fa = $Fb
    ElseIf ($Fc - $Fb > 0 And $Fd - $Fc >= 0) Or ($Fb - $Fa >= 0 And $Fc - $Fb >= 0) Then
    $d = $c
    $Fd = $Fc
    EndIf

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

    $dx = ($d - $a) / 3
    $b = $a + $dx
    $c = $d - $dx
    WEnd
    EndSwitch

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

    Return SetExtended($n, ($a + $b) / 2)
    EndFunc ;==>_Lok_Extr

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

    ; #FUNCTION#=================================================================================
    ; Name...........: _Bisektion
    ; Description ...: Berechnet die Nullstelle in einem Intervall numerisch
    ; Methode: Bisektionsverfahren (Dichotomie)
    ; Syntax.........: _Bisektion($F_X, $a, $b)
    ; Return values .: X-Wert der Nullstelle
    ; @Extended = Anzahl Iterationen
    ; Parameters.....: $F_X: String einer Funktionsdefinition abhängig von x
    ; $a: linke Suchbereichsgrenze
    ; $b: rechte Suchbereichsgrenze
    ; Requirements ..: Funktion float _Fx( string F(x), float x )
    ; Global $FLT_EPSILON = float
    ; Author ........: AspirinJunkie
    ;============================================================================================
    Func _Bisektion($F_X, $a, $b)
    Local $m, $fm, $n

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

    While True
    $n += 1
    $m = ($a + $b) / 2
    $fm = _Fx($F_X, $m)

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

    If Abs($fm) < $FLT_EPSILON ^ (1 / 1.1) Or Abs($a - $b) < $FLT_EPSILON ^ (1 / 1.1) Then ExitLoop

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

    If $fm < 0 Then
    $a = $m
    Else
    $b = $m
    EndIf
    WEnd
    Return SetExtended($n, $m)
    EndFunc ;==>_Bisektion

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

    ; #FUNCTION#=================================================================================
    ; Name...........: _Abl1
    ; Description ...: Berechnet die 1. Ableitung einer Funktion F(x) an der Stelle x
    ; Methode: "zentraler Differenzenquotient"
    ; Syntax.........: _Abl1($F_X, $x)
    ; Return values .: Wert der 1. Ableitung
    ; Parameters.....: $F_X: String einer Funktionsdefinition abhängig von x
    ; $x: Wert der Funktionsvariable
    ; Requirements ..: Funktion float _Fx( string F(x), float x )
    ; Global $FLT_EPSILON = float
    ; Author ........: AspirinJunkie
    ;============================================================================================
    Func _Abl1($F_X, $x)
    Local Const $h = $FLT_EPSILON ^ (1 / 3)

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

    Return (_Fx($F_X, $x + $h) - _Fx($F_X, $x - $h)) / (2 * $h)
    EndFunc ;==>_Abl1

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

    ; #FUNCTION#=================================================================================
    ; Name...........: _Abl2
    ; Description ...: Berechnet die 2. Ableitung einer Funktion F(x) an der Stelle x
    ; Methode: "zweite Differenz"
    ; Syntax.........: _Abl1($F_X, $x)
    ; Return values .: Wert der 2. Ableitung
    ; Parameters.....: $F_X: String einer Funktionsdefinition abhängig von x
    ; $x: Wert der Funktionsvariable
    ; Requirements ..: Funktion float _Fx( string F(x), float x )
    ; Global $FLT_EPSILON = float
    ; Author ........: AspirinJunkie
    ;============================================================================================
    Func _Abl2($F_X, $x)
    Local Const $h = $FLT_EPSILON ^ (1 / 3)

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

    Return (_Fx($F_X, $x + $h) - 2 * _Fx($F_X, $x) + _Fx($F_X, $x - $h)) / ($h ^ 2)
    EndFunc ;==>_Abl2

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

    ; #FUNCTION#=================================================================================
    ; Name...........: _GET_FLT_EPSILON
    ; Description ...: Berechnet den binären Rundungsfehler und damit die Rechengenauigkeit
    ; Syntax.........: _GET_FLT_EPSILON
    ; Return values .: Epsilon
    ; Author ........: AspirinJunkie
    ;============================================================================================
    Func _GET_FLT_EPSILON()
    Local $x = 1

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

    While True
    $x /= 2
    If 1 + $x <= 1 Then ExitLoop
    WEnd

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

    Return $x
    EndFunc ;==>_GET_FLT_EPSILON

    [/autoit]

    Edit: Hab mal aus eigenem Interesse heraus mal noch eine erste Möglichkeit eingebaut mit der lokale Extrema ohne Ableitung gefunden werden können.

    3 Mal editiert, zuletzt von AspirinJunkie (15. Januar 2010 um 23:20)

  • Erstmal natürlich Danke für die ganze Arbeit :)
    Dein Script sieht echt gut aus. Nur finde ich, dass das Newton-Verfahren deutlich bessere Ergebnisse liefert UND schneller arbeitet.
    Ich hab das Newton-Verfahren nochmal auf dein Script zurechtgeschrieben, sodass man es einfach einsetzen kann:

    Spoiler anzeigen
    [autoit]


    ; #FUNCTION#=================================================================================
    ; Name...........: _Newton
    ; Description ...: Berechnet die Nullstelle in einem Intervall numerisch
    ; Methode: Newton-Verfahren
    ; Syntax.........: _Newton($F_X, $a, $b)
    ; Return values .: X-Wert der Nullstelle
    ; @Extended = Anzahl Iterationen
    ; Parameters.....: $F_X: String einer Funktionsdefinition abhängig von x
    ; $a: linke Suchbereichsgrenze
    ; $b: rechte Suchbereichsgrenze
    ; Requirements ..: Funktion float _Fx( string F(x), float x )
    ; Funktion float _Abl1( string F(x), float x )
    ; Global $FLT_EPSILON = float
    ; Author ........: Ludwig Waffenschmidt
    ;============================================================================================
    Func _Newton($F_X, $a, $b)
    Local $m = $a, $fm, $fam, $n

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

    While True
    $n += 1
    $fm = _Fx($F_X, $m)
    $fam = _Abl1($F_X, $m)
    $m -= $fm / $fam

    If Abs($fm) < $FLT_EPSILON ^ (1 / 1.1) Or Abs($a - $b) < $FLT_EPSILON ^ (1 / 1.1) Then ExitLoop

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

    If $fm < 0 Then
    $a = $m
    Else
    $b = $m
    EndIf
    WEnd
    Return SetExtended($n, $m)
    EndFunc ;==>_Bisektion

    [/autoit]

    Die Extrema-Suche ist auch schon ziemlich gut, nur sind die Ergebnisse dort auch noch recht ungenau.

    mfg
    Ludwig

  • Wie gesagt:
    Das Bisektionsverfahren war extra als Platzhalter gedacht, so dass du einfach das Verfahren austauschen kannst.
    Wie ich schon schrieb ist es klar dass das Newton-Verfahren viel schneller konvergiert.
    Allerdings ist eine Konvergenz nicht garantiert so dass man bei ungünstigen Funktionen und Grenzen schnell in Endlosschleifen festhängen kann.
    Entweder man bricht da bei ner festgelegten Anzahl an Iterationen automatisch ab, was heißen würde man hat keine Lösung, oder man weicht gleich auf stabilere Algorithmen aus.
    Daher mein Hinweis auf Regula Falsi.
    Mal abgesehen davon das die Ableitung aufgrund des Rundungsfehler ungenauer ist als die reine Funktionsberechnung und dieser Fehler mitgezogen wird.

  • Okay...
    Ich hab jetzt auch mal Regula Falsi gemcht und das ist wirklich gut. Danke für den Tip, es findet schnell und genau die Nullstellen :).

    Spoiler anzeigen
    [autoit]


    ; #FUNCTION#=================================================================================
    ; Name...........: _RegulaFalsi
    ; Description ...: Berechnet die Nullstelle in einem Intervall numerisch
    ; Methode: Regula Falsi
    ; Syntax.........: _RegulaFalsi($F_X, $a, $b)
    ; Return values .: X-Wert der Nullstelle
    ; @Extended = Anzahl Iterationen
    ; Parameters.....: $F_X: String einer Funktionsdefinition abhängig von x
    ; $a: linke Suchbereichsgrenze
    ; $b: rechte Suchbereichsgrenze
    ; Requirements ..: Funktion float _Fx( string F(x), float x )
    ; Global $FLT_EPSILON = float
    ; Author ........: Ludwig Waffenschmidt
    ;============================================================================================
    Func _RegulaFalsi($F_X, $a, $b)
    Local $m, $n, $x1 = $a, $y1 = _Fx($F_X, $a), $x2 = $b, $y2 = _Fx($F_X, $b), $c

    While True
    $c += 1

    $m = (($y1 - $y2) / ($x1 - $x2))
    $n = $y1 - $m * $x1

    $xNew = (0 - $n) / $m ;y = mx+n --> x = (y-n)/m
    $yNew = _Fx($F_X, $xNew)
    If $yNew = 0 Then
    ExitLoop
    ElseIf $yNew > 0 Then
    $x1 = $xNew
    $y1 = $yNew
    ElseIf $yNew < 0 Then
    $x2 = $xNew
    $y2 = $yNew
    EndIf

    If Abs($yNew) < $FLT_EPSILON ^ (1 / 1.1) Or Abs($x1 - $x2) < $FLT_EPSILON ^ (1 / 1.1) Then ExitLoop
    WEnd
    Return SetExtended($c, $xNew)
    EndFunc ;==>_RegulaFalsi

    [/autoit]

    Hättest du vielleciht auch noch eine Idee, wie man die Extrema verbessern könnte ?

    mfg
    Ludwig

  • Hättest du vielleciht auch noch eine Idee, wie man die Extrema verbessern könnte ?

    Naja prinzipiell sucht man Extrema über die normalen Nullstellensuchalgorithmen (also Newton, Sekantenverfahren, Regula-Falsi). Nur halt das man statt der Funktionswerte die Werte der 1. Ableitung an den jeweiligen Stellen nimmt und die für die Tangenten die Werte der 2. Ableitung.
    Mich hatte allerdings eine Möglichkeit interessiert, welche ohne Ableitung auskommt.
    Da gibt es als einfachste Variante die das man einfach durchläuft und aufeinanderfolgende Werte vergleicht und so den größten bzw. kleinsten Wert herausfindet.
    Das ist logischerweise äußerst ineffektiv weshalb ich mir überlegt habe wie man das anders machen könnte.
    Hab deswegen den Suchbereich in 3 Teile gesplittet und die jeweiligen 3 Anstiege verglichen.
    So kann ich einen der 3 Bereiche ausschließen und somit den Suchbereich iterativ verkleinern (so ähnlich wie Bisektion).
    Das ist noch nicht sehr effektiv aber es war auch nur aus reinem Interesse heraus.
    Willst du es verbessern dann Nullstellensuche auf der 1. Ableitung.
    Wirst aber nicht die Genauigkeit erreichen wie bei der reinen Funktionsberechnung weil die Ableitung durch den Rundungsfehler eine höhere Ungenauigkeit aufweist.
    Sollte aber dennoch für ausreichende Genauigkeit sorgen.

  • Okay, Danke, Danke, Danke, das schaff ich, ist ja wirklich nur überall wo vorher _Fx stand _Abl1 hinschreiben und überprüfen obs ein Minima oder Maxima ist sollte auch einfach sein. ;)
    Der Wert ist ja trotz der nur angenäherten 1. Abl noch ziemlich genau, wird dann auch in der nächsten Version von Unicalc Grafik drin sein.

    Falls jemand Lust hätte, Unicalc Grafik zu übersetzen, wäre ich auch froh :). Hab ja erst Deutsch, Englisch, Französisch, Spanisch und Niederlänisch. Also wenn jemand Lust hat das zu übersetzen : :) , ist ja auch nicht viel ...

    mfg
    Ludwig

  • Ich kann mir die Sachen irgendwie nur als normale Datei runterladen...
    ist das normal?

    [autoit]


    While $Life = True
    $nMSG = BrainGetMsg()
    Switch $nMSG
    Case $Idea
    _Convert_Idea2Code()
    EndSwitch
    WEnd

    [/autoit]