Intervallschachtelung

Hallo

Ich bin etwas am verzweifeln. Ich soll ein Programm schreiben, das mittels Intervallschachtelung in Java die Nullstellen einer vorgegeben (im Programmcode vorhandene) Funktion errechnet. Das soll wie ich es verstanden habe über eine rekursive Methode gelöst werden. Meine ganzen Versuche scheitern aber…

  1. Das Programm dürfte ein eigentlich sehr einfaches und kurzes Programm sein (die Vorübungen zeigen das [max 15-20 Zeilen Code] bisher. Ist aber eine Zusatzaufgabe)
  2. Die eigentlich Nullstelle ist bei 1,05… mein Programm kommt ständig auf 1,25. Egal was ich mache.

Also bisher bin ich so vorgegangen:
Die Main-Methode ruft die Methode „nullstelle“ auf. Parameter sind die Intervallgrenzen int1 und int2 sowie das Abbruchkriterium, das beschreibt, bei welcher Genauigkeit abgebrochen werden soll.
Die Methode „nullstelle“ berechnet nun rekursiv die Grenzen so lange neu, bis sich das Abbruchkriterium erfüllt. Einige meiner Ansätze machen das auch ganz gut, nur dass dann durch die return-Anweisung die Lösung sozusagen überschrieben wird mit den älteren Werten der zuvor aufgerufenen Methode.

Kann ich das umgehen oder gibt es ne andere Lösungsstrategie?

Ich hoffe, ich konnte halbwegs klarstellen, was ich meine…

Gruss Olli

PS: Hab jeglichen Code inzwischen in das Datennirvana geschickt, deshalb kein Code angehängt…

Hallo!

Wenn du einen Algorithmus haben willst, der immer funktioniert, ist es nicht ganz so einfach (es sei denn ich sehe eine einfachere Lösung nicht). Hier meine Lösung: Das Hauptprogramm ist in der Datei „Intervallschachtelung“ und die Klasse Intervall in der Datei „Intervall“:

Datei „Intervall“:

public class Intervall
{
public Intervall( float set_i_start,float set_i_end )
{
i_start = set_i_start;
i_end = set_i_end;
}

public float i_start;
public float i_end;

public Intervall next;
}

Datei „Intervallschachtelung“:

public class Intervallschachtelung
{
private Intervall current;
private Intervall last;

private int approximation;

private int test_limit;

public Intervallschachtelung( String[] args )
{
approximation = Integer.parseInt( args[0] );

current = new Intervall( Float.parseFloat( args[1] ),Float.parseFloat( args[2] ) );
last = current;

test_limit = Integer.parseInt( args[3] );
}

private float getValue( float x )
{
return( 1.5f*x + 3f ); //Funktionswert berechnen
}

private boolean goodApproximation( float y )
{
if( y == 0f || ( Math.abs( y )

z.B.

„…\java Intervallschachtelung 3 -10 10 10000“

Durchläuft mit Genauigkeit von zwei Nachkommastellen (-> 0.00irgendwas=3 führende Nullen=„Genauigkeit 3“), wobei das Intervall [-10,10] durchsucht wird und maximal 10000 mal ein Wert ausgerechnet wird, bevor das Programm abbricht.

Florian

Etwas unleserlich
Ich merke gerade der Code ist ein bißchen unansehnlich, weil Wer-Weiss-Was Leerzeichen und so killt…

Florian

PRE Tag
Hi,

dafür gibts das Tag, dann ist Schluss mit Whitespace killen…

Gruss,

Herb

Hallo Florian

Vielen Dank für deine Mühen. Ich denke, dass ich damit was anfangen kann!
Das Programm sieht ja recht kompliziert aus, aber da steig ich sicher noch durch. Muss es mir mal in aller Ruhe zu Gemüte führen.

Gruss Olli

Hallo!

Das Programm sieht ja recht kompliziert aus, aber da steig ich
sicher noch durch. Muss es mir mal in aller Ruhe zu Gemüte
führen.

Hier ein paar techn. Details:

Zur Klasse „Intervall“:

Ist nur eine Klasse um ein Intervall zu speichern.

-Besitzt nur einen Konstruktor zum Setzen der Intervallgrenzen.

Zur Klasse „Intervallschachtelung“:

Hauptprogramm.

-Besitzt eine main - Methode für den Programmstart. Ruft den Konstruktor auf, um mit den Parametern des Aufrufs die Systemparameter zu setzen (Approximation, Intervall etc.). Anschließend wird mit findValue die Nullstelle gesucht.

-getValue berechnet den zu einer Stelle x gehörenden y - Wert

-goodApproximation prüft, ob eine gegebene Annäherung an eine Nullstelle ausreichend genau ist. Dazu wird der y - Wert der approximierten Stelle mit einer Zehnerpotenz multipliziert um zu sehen, ob eine gewisse Genauigkeit erreicht ist (pow( 10,approximation) bedeutet 10^approximation).

findValue ist der eigentliche Analyse-Algorithmus. Er implementiert eine verkettete Liste von Intervallen in der die zu untersuchenden Intervalle eingetragen werden. Technisch funktioniert diese Liste wie eine FIFO - Warteschlange (first in, first out). Der Algorithmus funktioniert nun nach folgendem Prinzip (siehe while - Schleife): „Hole ein neues Intervall aus der Liste. Berechne den Funktionswert f(x) in der Mitte des Intervalls. Ist das eine ausreichend gute Näherung für die Nullstelle? Wenn ja: Toll, gib’ das Ergebnis aus. Wenn nein: Füge das Intervall [Intervallstart,x] und das Intervall [x,Intervallende] zur Liste hinzu. Starte wieder von vorne“.
Darüber hinaus zählt die Schleife ihre Durchläufe mit, um nach einer bestimmten Grenzanzahl (test_limit) abzubrechen - dient nur der Sicherheit. Ist die Grenze überschritten, bricht der Analyse-Algorithmus ab und gibt die beste gefunde Näherung an die Nullstelle zurück (best_approximation).

Es ist wichtig zu verstehen, warum ich das so und nicht anders implementiert habe. Dein rekursiver Ansatz funktioniert nämlich schon rein theoretisch nicht! Warum? Nun ja: Ein rekursiver Algorithmus für dieses Problem wäre eigentlich nichts anderes als mein Lösungsalgorithmus mit einer LIFO - Warteschlange - auch „Stack“ genannt. Das liegt daran, dass sich jeder rekursive Algorithmus durch einen Stack nicht-rekursiv ausformulieren lässt (das macht übrigens der Compiler mit einem rekursiven Algorithmus den du in den Quellcode gefuscht hast; deswegen gibt’s bei zu hoher Rekursionstiefe auch mal einen „Stack-overflow“). Das Problem: In einer solchen Implementierung würde nur eine Hälfte des angegebenen Intervalls bis zum Verrecken untersucht werden bevor der Computer auf die Idee kommt, die andere Hälfte zu untersuchen - weil alle bei der Untersuchung des Intervalls entstehenden neuen Intervalle sozusagen „an den Anfang“ der Liste gesetzt werden. Dann gibt’s zwei Möglichkeiten wie das ganze ausgeht: Entweder der Rechner rechnet sich bis in alle Ewigkeit dumm und dämlich weil die Nullstelle gar nicht in dieser einen Intervallhälfte liegt oder er findet durch Glück irgendwann die Nullstelle, weil sie zufälligerweise in diesem Intervall liegt - erinnert mich ein bißchen an russisches Roulette :smile:.
Mit meiner Methode - also mit einer FIFO - Schleife - werden aber abwechselnd das linke und rechte Intervall untersucht. Somit kann dieses Problem nicht auftauchen und der Algorithmus funktioniert!
Übrigens mit Vorzeichenwechseln kann man auch nicht nach der Nullstelle suchen: Bei einer Funktion wie z.B. x^2 gibt es nämlich keinen Vorzeichenwechsel bei der Nullstelle, weil die Nullstelle zweifach - also gerade - gesetzt ist.

Florian