# Eine mathematische Funktion als Argument für eine Methode - Matheparser?



## Screen (31. Mai 2010)

Hallo

Ich benutze eine Klasse um Nullstellen zu suchen. Ein Intervall wird halbiert ,bis Nullstellen gefunden werden.
Das Problem ist hier,dass ich nur eine Nullstelle finden kann, auch wenn die Funktion mehrere hat.
Mit verschiedenen Intervallen habe ich das ausprobiert, sollte aber im Intervall keine Nulstelle liegen bekomme ich eine Fehlermeldung: java.lang.StackOverflowError

Könnte mir jemand verraten, wie ich mehrere Nullstellen abfragen kann? Oder wie ich diesen Fehler vermeiden kann,wenn ich Intervalle ohne Nullstellen abfrage?



```
// Die Nulstellensuche
public class Nullstellensuche {

  /**
   * Die (stetige) Funktion für die Nullstellen gesucht werden sollen.
   */
  private Funktion funktion;
  
  /**
   * Genauigkeit, mit der Nullstellen von <code>funktion</code> berechnet werden
   * sollen.
   */
  private double genauigkeit = 0.000001;
  
  /**
   * Erzeugt eine neue Nullstellensuche mit der gegeben 
   * stetige reelwertigen <code>funktion</code>. Die Nullstelle
   * kann nährungsweise bis zur angegeben <code>genauigkeit</code>
   * berechnet werden.
   * 
   * @param funktion eine <code>stetige</code> Funktion
   */
  public Nullstellensuche(Funktion funktion, double genauigkeit) {
    this.funktion = funktion;
    this.genauigkeit = genauigkeit;
  }

  /**
   * Sucht eine Nullstelle in dem gegeben Intervall [links, rechts] und
   * findet sie auch, wenn die Vorzeichen von f(links) und f(rechts) verschieden sind,
   * dass heisst, wenn f(links) * f(rechts) < 0 sind.
   */
  public double sucheNullstelle(double links, double rechts) {
    double mitte = (links + rechts) / 2.0;
    
    if ( Math.abs( funktion.f(mitte) ) < genauigkeit ) {
      return mitte;
    } else if ( funktion.f(mitte) * funktion.f(rechts) < 0 ) {
      return sucheNullstelle(mitte, rechts);
    } else {
      // man überzeuge sich hier, dass f(mitte) * f(links) < 0 gelten muss!

       return sucheNullstelle(links, mitte);
    }
  }
}
```


```
//Die Funktion
 public double f(double x) {
       
        return 2*Math.pow(x, 4)-1;
    }
```


```
// Die Abfrage der Nullstellen 
        double r= n.sucheNullstelle(-100,0);
        b= Math.round(r*100)/100.0);
        System.out.println(b);

        double r2= n.sucheNullstelle(0,100);
        b2= Math.round(r2*100)/100.0);
        System.out.println(b2);
```


Bei z.B n.sucheNullstelle(-100,-90); gibt es den Fehler von  java.lang.StackOverflowError
Ich kann aber nicht wissen, ob zwischen -100 und -90 einer ist oder nicht..sollte keiner vorhandne sein, stürzt das Prog ab.

Help pls...


----------



## U2nt (31. Mai 2010)

Ich weiß nicht, kann auch sein das das dieser Rekursions zeug is, kenn mich damit nicht aus, aber mir kommen diese:


```
public double sucheNullstelle(double links, double rechts) {
    double mitte = (links + rechts) / 2.0;
    
    if ( Math.abs( funktion.f(mitte) ) < genauigkeit ) {
      return mitte;
    } else if ( funktion.f(mitte) * funktion.f(rechts) < 0 ) {
      return sucheNullstelle(mitte, rechts);
    } else {
      // man überzeuge sich hier, dass f(mitte) * f(links) < 0 gelten muss!
 
       return sucheNullstelle(links, mitte);
    }
  }
}
```

komisch vor, du returns nochmal den Funktionsaufruf - also wie gesagt, kann auch sein das du da irgendwas mit Rekursion machst, ansonsten ..


----------



## Screen (31. Mai 2010)

Der Code von oben ist funktionsfähig ,er gibt mir eine richtige Nullstelle aus... ich brauche aber mehr, eigentlich alle Nullstellen der Funktionen. 
Mit unterschiedlichen Intervallen funktioniert das leider nicht !


----------



## alien0matic (31. Mai 2010)

Dein Problem ist, dass du davon ausgehst, dass auf dem Interval eine Nullstelle vorhanden ist. Ist keine vorhanden rufst du deine Methode immer weiter auf bis der Speicher nichtmehr ausreicht. Hier fehlt eine Abbruchbedingung.


----------



## Screen (31. Mai 2010)

alien0matic hat gesagt.:


> Dein Problem ist, dass du davon ausgehst, dass auf dem Interval eine Nullstelle vorhanden ist. Ist keine vorhanden rufst du deine Methode immer weiter auf bis der Speicher nichtmehr ausreicht. Hier fehlt eine Abbruchbedingung.



Das habe ich mir auch schon gedacht...leider ist mir die Bedingung nicht bekannt. Es kann keine If Befindung mit < oder > 0 schreiben. 
Wie könnte diese aussehen?

So in der Art If( ErgebnisvonNullstellensuche== keine Zahl) {   break ; } ..aber wie genau?


----------



## ne0n2005 (31. Mai 2010)

Da wollt ich jetzt den google link zur "Rekursion" posten, aber dir haben das garnichtmehr


----------



## Screen (31. Mai 2010)

ne0n2005 hat gesagt.:


> Da wollt ich jetzt den google link zur "Rekursion" posten, aber dir haben das garnichtmehr



ja egal.. meine Klasse habe ich schon. Nun muss ich alle Nullstellen finden können  Welche Bedingung könnte das nur sein? (2 posts höher)


----------



## alien0matic (31. Mai 2010)

Naja spätestens wenn links und rechts gleich sind wird man nichts mehr finden 
Da du hier aber mit double werten rechnest müsstest du hier auch eine Genauigkeit mit einbeziehen. Allerdings müsste auch der return wert ein anderer sein, denn es gibt 2 Möglichkeiten: Nullstelle oder nichts.
Ich würde hier also ein Double Objekt zurückgeben.


----------



## Final_Striker (31. Mai 2010)

Screen hat gesagt.:


> Das habe ich mir auch schon gedacht...leider ist mir die Bedingung nicht bekannt. Es kann keine If Befindung mit < oder > 0 schreiben.
> Wie könnte diese aussehen?
> 
> So in der Art If( ErgebnisvonNullstellensuche== keine Zahl) {   break ; } ..aber wie genau?



Du musst die Suche abbrechen sobald der Abstand der Punkte links und recht eine festgelegte Länge unterschreitet.


----------



## ne0n2005 (31. Mai 2010)

Du könntest einfach behaupten, dass wenn er 1000mal das Intervall halbiert hat und immer noch nicht in deinem Genauigkeitsbereich ist es keine Nullstelle gibt.
Jedoch ist das ein bisschen schwer zu Implementieren. Ein einfacher zähler, wie oft die Methode schon aufgerufen wurde würde vielleicht sogar auch Funktionieren, aber um es schön zu machen müsste man der Methode glaube ich einen Zähler als Parameter mitgeben, damit jede Verzweigung ihren eigenen Zähler bekommt.

edit: Es sollte in dem Forum einen Knopf "Dummes Kommentar sofort unwiederruflich löschen und alle User die es gelesen haben aufspüren und zum Schweigen bringen lassen" geben. Denn natürlich hat sich dann nach diesen 1000 durchgängen der linke und der rechte Wert angenähert.
Ich glaube ich sollte einfach nur noch Fern gucken wenn ich krank bin


----------



## ne0n2005 (31. Mai 2010)

Mein Vorhaben den Link zur Rekursion von google zu posten sollte auch bloß der reinen Belustigung dienen, denn früher kam dann immer eine Endlosschleife  "Meinten sie: Rekursion". Aber irgendwie gibt es das nun leider nichtmehr.


----------



## Screen (31. Mai 2010)

Also Ich kann den Fehler vermeiden ,wenn ich die Bedingung:


```
if (funktion.f(links) == funktion.f(rechts))
     {
           return 0;
     }
```


die Nullstellensuche -Methode einbaue.
Ich kann aber keine 0 ausgeben,wenn im Intervall keine Nullstelle ist  
Trotzdem habe ich jetzt nur eine Nullstelle :<


----------



## alien0matic (31. Mai 2010)

Screen hat gesagt.:


> Also Ich kann den Fehler vermeiden ,wenn ich die Bedingung:
> 
> 
> ```
> ...





```
if (funktion.f(links) == funktion.f(rechts)) //möglich, dass das nie eintritt.
     {
           return 0; //und wenn die nullstelle wirklich 0 ist? Wie unterscheidest du das?
     }
```


----------



## ne0n2005 (31. Mai 2010)

Die Methode hat doch auch nur einen Rückgabewert, ich weiß jetzt gerade nicht mehr genau, aber müsste das dann nicht die zuletzt gefundene Nullstelle sein ? Also wenn der Stack dann irgendwann runterbricht und die Ergebnisse zurückliefert.


----------



## Screen (31. Mai 2010)

Ne klar...

Es stehen aber immer noch die Fragen offen:
1. Wie soll die Abbruchbedingung aussehen? bzw. der returnwert
2. Wie frage ich alle anderen Nullstellen des selben Intervalls ab?


----------



## Final_Striker (31. Mai 2010)

Nimm am besten als Rückgabewert 
	
	
	
	





```
Double.MAX_VALUE;
```
 oder 
	
	
	
	





```
Double.MIN_VALUE;
```
 (größte oder kleinster double Wert) da an diesen Stellen keinen Nullstelle liegen kann. ;-)


----------



## ne0n2005 (31. Mai 2010)

[Java]
  public double sucheNullstelle(double links, double rechts) {
    double mitte = (links + rechts) / 2.0;

    //Rekursionsverankerung 1:
    if (funktion.f(links) == funktion.f(rechts))  {
        //wenn es nicht möglich war eine Nullstelle zu finden
        return 0;
    }
    //Rekursionsverankerung 2:
    if ( Math.abs( funktion.f(mitte) ) < genauigkeit ) {
        // wenn eine Nullstelle gefunden wurde
        return mitte;
    }


    if ( funktion.f(mitte) * funktion.f(rechts) < 0 ) {
        //wenn zwischen der mitte und rechts ein Vorzeichenwechsel stattfindet
        //es dort also eine Nullstelle geben muss
        return sucheNullstelle(mitte, rechts);
    }  
    if( funktion.f(mitte) * funktion.f(links) < 0 )
        //wenn zwischen der mitte und links ein Vorzeichenwechsel stattfindet
        //es dort also eine Nullstelle geben muss
        return sucheNullstelle(links, mitte);
    }
    //wenn jetzt in keines der beiden letzten if´s gegangen wurde gibt es keine Nullstelle 
  }
[/Java]


ok vielleicht den Code hier oben garnicht so ernst nehmen. Beim schreiben ist mir glaub ich schon etwas unschönes aufgefallen: Undzwar interessierst du dich nur für die rechte Seite, und testest diese dann mit deinem Vorzeichenwechsel-Trick. Gibt es nun aber rechts vom Mittelpunkt 2 Nullstellen, so dass das Vorzeichen von f(mitte) und f(rechts) das gleiche ist, so suchst du links nach einer Nullstelle. Sollte es links keine geben, findest du garkeine.

Ich glaube es wäre fast sinnvoll die Reukstion wie folgt aufzubauen:

Wenn keine Nullstelle in der Mitte vorliegt und rechts nicht gleich links sind, dann rufe dich selbst noch einmal mit  links und mitte UND mitte und rechts auf.

Ich weiß ja nicht aus welchem bereich du anfangs mit rechts und links kommst, jedoch kann es glaube ich sein, dass es nicht immer fehlerfrei funktioniert zu schauen ob sich zwischen rechts und der mitte das vorzeichen gedreht hat.


----------



## Screen (1. Jun 2010)

Hallo

Ich habe das Problem teilweise gelöst.

Die Methode f gibt einen doublewert ,also die lösung einer funktion zurück.
Wie könnte ich dieser Methode aber eine Funktion übergeben?
Ich habs mit dme Douple-Parse versucht, das geht aber nicht.
Wie kann ich z.B. 1*Math.pow(x, 4)+2 diese Funktion dieser MEthode übergeben,damit sie das Ergebnis zurückliefert?
z.b. ich gebe mit der Scannermethode eine Gleichung ein, es ist aber ein String. Darum kann ich die Funktion der Methode f nicht übergeben,damit sie das Ergebnis mit dme x zurücklifert.


```
public double f(double x) {
        
       // return 1*Math.pow(x, 4)+2*Math.pow(x, 3)-13*Math.pow(x, 2)-14*Math.pow(x, 1)+24;
       
        return x*x-2;
    }
```

Wie mache ich das?
return "x*x-2"; geht nicht !
return Double.parseDouble("x*x-2") geht nicht!

Wie gebe ich nun der Methode eine Funktion?


----------



## Michael... (1. Jun 2010)

Screen hat gesagt.:


> z.b. ich gebe mit der Scannermethode eine Gleichung ein, es ist aber ein String.


Nach einem Mathe/Formel - Parser googlen oder selbst einen schreiben


----------



## ne0n2005 (1. Jun 2010)

Hey, fuktioniert die rekursive Suche der Nullstellen denn jetzt, weil ich war jetzt der Meinung, dass sie z.B. für f(x) = x²-1 nicht gehen sollte, wenn du die Suche mit (-500,200) aufrufst.


----------



## Screen (1. Jun 2010)

Die Klasse funktioniert nun... naja ich bekomme wenigstens 2 nullstellen raus. Wenn ich von dem Intervall -100 bis 0 und von 0 bis +100 abfrage. 

Leider weiß ich nicht wie ich per Scanner(methode) eine neue Funktion der Methode f übergeben soll


----------



## Marco13 (1. Jun 2010)

Also das 
if (funktion.f(links) == funktion.f(rechts)) 
als Abbruchbedingung ist glaub' ich nicht so gut. Spätestens bei nicht-stetigen Funktionen (bei denen die Sprungstelle genau zwischen links und rechts liegt) dürfte es das raushauen. Sowas wie
if (Math.abs(links-rechts) < 1e8) abbruch
würde mir eher einleuchten.

Für die Information "es gibt dort keine Nullstelle" bietet sich IMHO die Rückgabe von Double.NaN an.... 

```
double berechne(...)
{
    if (Math.abs(links-rechts) < 1e8) return Double.NaN;
    ...
}


// Aufruf
double nullstelle = berechne(...);
if (Double.isNaN(nullstelle)) System.out.println("Da is nix");
```


----------

