Funktion auf mehrere dateien verpacken- wo fehler?



  • while(/*hier ein passendes Abbruchkriterium einsetzen*/)
    {
      double fx=0,fxA=0;
      for(int i=0;i<=grad;++i)
      {
        double p=potenz(xnull,i);
        fx +=koeff[i]*p;  //summiert f(x)
        fxA+=koeffA[i]*p; //summiert f'(x)
      }
      xnull=xnull-fx/fxA; //neuer Näherungswert
    }
    return xnull;
    

    Das wäre ein Ansatz - eventuell noch optimierungswürdig



  • Naja, das hier stimmt nicht so ganz

    fxA+=koeffA[i]*p;
    

    eher so

    fx +=koeff[i] * potenz(xnull,i);  //summiert f(x)
    if( i>0) fxA+=koeffA[i] * potenz(xnull,i-1); //summiert f'(x)
    


  • Alles eine Frage der Organisation 😉 (sprich: Um die Funktionswerte zu berechnen, mußt du dir einig sein, welcher Koeffizient wo steht soll - und da macht es imho Sinn, es einheitlich zu lösen)



  • Ok ich habe die Änderungen nun soweit vorgenommen. Aber mit einer for statt while weil mir keine bedingung auf die schnelle einfiel. So kann der programmierer udn später durch eingabe der user die anzahl der durchläufe festlegen.
    Das sieht so aus:

    double naeherung(int grad, double *koeff, double *koeffA, double xnull)
    {
    for(int i=0;i<1;i++)
    {
      double fx=0,fxA=0;
      for(int i=0;i<=grad;++i)
      {
        double p=potenz(xnull,i);
        fx +=koeff[i] * potenz(xnull,i);  //summiert f(x)
        if( i>0) fxA+=koeffA[i] * potenz(xnull,i-1); //summiert f'(x)
      }
      xnull=xnull-fx/fxA; //neuer Näherungswert
    }
    return xnull;
    }
    

    Das ergibt auch einen netten wert.
    Ich habe als Funktion folgendes verwendet:
    2*X^2+3*X
    d.h.: grad=2 und Koeff sind 2, 3.
    Und als Näherungswert -2. (Laut plotter sind -1,5 und 0 meine Nullstellen.)
    Wieso errechnet das Verfahren (so wie ihr es konstruiert habt) denn nun -0,25...
    Das läuft (so vermute ich gegen 0) aber -1,5 liegt doch näher...
    ...irgendwie hab ich mich da jetzt verhaspelt mit dem for. Da hab ich nun dank euch zwei von^^ wieso das nun?
    Generell soll die Näherung ja sinnvoll sein. Also sagen wir 5x nähern - das wäre ja dann als ergebnis für den anfang verkraftbar.

    Generell: Aus welchem Grund hast du die while() eingebunden?



  • t1m0n schrieb:

    Generell: Aus welchem Grund hast du die while() eingebunden?

    Weil man damit einfacher ein Abbruchkriterium definieren kann (z.B. laufe solange, bis die Abweichung kleiner ist als epsilon):

    do
    {
      xnalt=xnull;
      ...
      xnull=xnull-fx/fxA;
    }
    while(fabs(xnalt-xnull)>1e-10);
    


  • CStoll schrieb:

    t1m0n schrieb:

    Generell: Aus welchem Grund hast du die while() eingebunden?

    Weil man damit einfacher ein Abbruchkriterium definieren kann (z.B. laufe solange, bis die Abweichung kleiner ist als epsilon):

    do
    {
      xnalt=xnull;
      ...
      xnull=xnull-fx/fxA;
    }
    while(fabs(xnalt-xnull)>1e-10);
    

    Das verstehe nicht nicht. Und was ist fabs...



  • fabs ist der Betrag. Steht aber auch in der cppReferenz (aus dem Link).



  • Ok, habs gefunden - danke
    Und wozu dann 1e-10?
    Was genau definiert epsilon in diesem fall, oder wie jetzt?
    Hab die suche bei cppreference genutzt, aber keinen treffer gelandet



  • epsilon ist die Iterationsdifferenz (oder wie das richtig heißt). Das bedeutet einfach, dass die Schleife abbricht wenn sich das Ergebnis der Iteration um nicht mehr als epsilon ändert. Man nennt sowas auch ein Konvergenzkriterium.
    Bezüglich cppreference solltest du nur wegen pow oder fabs nachschauen.



  • t1m0n schrieb:

    Und wozu dann 1e-10?

    Das war nur ein Beispielwert für epsilon - Unterschiede unterhalb von 10-6 kannst du vernachlässigen.



  • Achso ok. Demnach bricht die Schleife aber spätestens ab wenn der speicherplatz von double halt nicht mehr ausreicht. Denn wenn sich das Ergebnis nicht mehr im Nachkommastellenbereich von double verändert ist die bedingung ja nicht mehr erfüllt und die schleife bricht ab, richtig?

    CStoll schrieb:

    t1m0n schrieb:

    Und wozu dann 1e-10?

    Das war nur ein Beispielwert für epsilon - Unterschiede unterhalb von 10-6 kannst du vernachlässigen.

    ja wie denn nun?? Ihr fangt an mich zu verwirren 😃



  • t1m0n schrieb:

    Achso ok. Demnach bricht die Schleife aber spätestens ab wenn der speicherplatz von double halt nicht mehr ausreicht. Denn wenn sich das Ergebnis nicht mehr im Nachkommastellenbereich von double verändert ist die bedingung ja nicht mehr erfüllt und die schleife bricht ab, richtig?

    Die Rechnung bricht ab, wenn sich der Wert (in der letzten Iteration) um weniger als eine bestimmte Größe geändert hat - wie groß diese maximale Änderung sein muß, bestimmst du (bei meinem Beispiel oben hatte ich 10-6 verwendet, weil mir das klein genug vorgekommen ist).



  • Kann du das an meine derzeitige funktion anpassen?:

    #include <iostream>
    #include "ableitung.h"
    using namespace std;
    /* 
    Diese Funktion führt das Newton'sche Näherungsverfahren durch
    */
    double naeherung(int grad, double *koeff, double *koeffA, double xnull)
    {
    for(int i=0;i<1;i++)
    {
      double fx=0,fxA=0;
      for(int i=0;i<=grad;++i)
      {
        double p=potenz(xnull,i);
        fx +=koeff[i] * potenz(xnull,i);  //summiert f(x)
        if( i>0) fxA+=koeffA[i] * potenz(xnull,i-1); //summiert f'(x)
      }
      xnull=xnull-fx/fxA; //neuer Näherungswert
    }
    return xnull;
    }
    

    Ich verstehe dann vielleicht wie du das genau meinst.
    Bin nämlich Neuling und lese zur Zeit MagnumC++ um es zu lernen. Dieses Beispiel habe ich genommen um C++ gleich so zu nutzen wie ich es auch möchte und nicht nur die stumpfen Beispiele abtippe.



  • Schmeiß einfach die for()-Schleife weg und pack ihren Inhalt in die do-while()-Schleife aus dem obigen Code (anstelle der ...) - dann hast du's.

    PS: Eventuell solltest du dir doch ein einfacheres Beispiel für den Einstieg suchen 😉



  • CStoll schrieb:

    PS: Eventuell solltest du dir doch ein einfacheres Beispiel für den Einstieg suchen 😉

    Hast du warscheinlich recht, aber die Herausforderung war halt gegeben durch meinen Mathelehrer - bot sich an^^
    Nun ist das ganze nicht fehlerfrei. Ich habe xnalt als xeins definiert, weil der neue wert bei uns in mathe als x1 bezeichnet wird - ist für mich somit leichter nachvollziehbar. Hab die Variable der variable dann auch nen Datentyp zugewiesen habe der Compiler sagt xeins undeclared:

    #include <iostream>
    #include "ableitung.h"
    using namespace std;
    /* 
    Diese Funktion führt das Newton'sche Näherungsverfahren durch
    */
    double naeherung(int grad, double *koeff, double *koeffA, double xnull)
    {
           double xeins;
           do
           {
            xeins=xnull;
            double fx=0,fxA=0;
            for(int i=0;i<=grad;++i)
            {
                    double p=potenz(xnull,i);
                    fx +=koeff[i] * potenz(xnull,i);  //summiert f(x)
                    if( i>0) fxA+=koeffA[i] * potenz(xnull,i-1); //summiert f'(x)
            }
           xnull=xnull-fx/fxA; //neuer Näherungswert
           }while(fabs(xeins-xnull)>1e-10);
           return xnull;
           }
    }
    


  • t1m0n schrieb:

    Hab die Variable der variable dann auch nen Datentyp zugewiesen habe

    Eventuell solltest du zwischendurch mal einen Deutschkurs besuchen *scnr*

    der Compiler sagt xeins undeclared:

    In welcher Zeile?



  • Oh sorry, bin halt auf den Code fixiert^^
    Der Compiler verweist in die Zeile der Bedingung:

    }while(fabs(xeins-xnull)>1e-10);
    


  • Ist da nicht eine geschweifte Klammer zu viel in der Funktion?
    Das p ist auch unnötig. Es wird ja nicht verwendet.
    Also

    double naeherung(int grad, double *koeff, double *koeffA, double xnull)
    {
      double xeins;
      do
      {
         xeins=xnull;
         double fxA=0;
         double fx = koeff[0];
         for(int i=1;i<=grad;++i)
         {
             fx  += koeff[i] * potenz(xnull,i);  //summiert f(x)
             fxA += koeffA[i] * potenz(xnull,i-1); //summiert f'(x)
         }
         xnull -= fx/fxA; //neuer Näherungswert
      } while(fabs(xeins-xnull) > 1.0e-10);
      return xnull;
    }
    

    Habs noch ein bischen umgebaut.



  • Noch was.
    Man sollte vielleicht noch eine weitere Abbruchmöglichkeit mittels einer maximalen Iterationsanzahl einführen, damit es bei Nichtkonvergenz keine Endlosschleife ergibt (falls das hier möglich ist).
    Hier mal die geänderte Version

    const int MaxIter = 100;
    
    double naeherung(int grad, double *koeff, double *koeffA, double xnull)
    {
      double xeins;
      int iter(0);
      do
      {
         xeins=xnull;
         double fxA=0;
         double fx = koeff[0];
         for(int i=1;i<=grad;++i)
         {
             fx  += koeff[i] * potenz(xnull,i);  //summiert f(x)
             fxA += koeffA[i] * potenz(xnull,i-1); //summiert f'(x)
         }
         xnull -= fx/fxA; //neuer Näherungswert
         ++iter;
      } while(fabs(xeins-xnull) > 1.0e-10 && iter < MaxIter);
      return xnull;
    }
    


  • Da ist ein logischer Fehler drinne...

    #include <iostream>
    #include <cmath>
    #include "ableitung.h"
    using namespace std;
    /* 
    Diese Funktion führt das Newton'sche Näherungsverfahren durch
    */
    const int MaxIter = 100;
    
    double naeherung(int grad, double *koeff, double *koeffA, double xnull)
    {
      double xeins;
      int iter(0);
      do
      {
         xeins=xnull;
         double fxA=0;
         double fx = koeff[0];
         for(int i=1;i<=grad;++i)
         {
             fx  += koeff[i] * potenz(xnull,i);  //summiert f(x)
             fxA += koeffA[i] * potenz(xnull,i-1); //summiert f'(x)
         }
         xnull -= fx/fxA; //neuer Näherungswert
         ++iter;
      } while(fabs(xeins-xnull) > 1.0e-10 && iter < MaxIter);
      return xnull;
    }
    

    Ich habe als Funktion folgendes verwendet:
    2*X^2+3*X
    d.h.: grad=2 und Koeff sind 2, 3. Näherungswert habe ich 2 und -2 verwendet.
    Der spuckt nun aber -3,77303e-012 bzw. bei 2 ohne - das ganze aus.
    Es sollte aber ein Wert herauskommen, die sich -1,5 oder 0 nähert da dies die beiden Nullstellen sind..

    Auch ist mir diese Zeile nicht bekannt:

    int iter(0);
    

    Wozu ist die gut - laut Compiler hat es was mit Container zu tun, hab dafür aber keinen verwendungszweck gefunden.. überflüssig und verwirrend stelle ich fest!?

    Und folgendes genauso:

    xeins=xnull;
         double fxA=0;
         double fx = koeff[0];
    

    wieso wird der wert von xnull xeins zugewiesen und wieso für den Array koeff 0 Plätze reserviert.. das ergibt doch alles keinen sinn...??

    Ich habe es nun so angepasst wie ich es verstehe, iter hab ich drinne gelassen weil es wohl wichtig ist^^ genaue bedeutung ist mir schleierhaft:

    #include <iostream>
    #include <cmath>
    #include "ableitung.h"
    using namespace std;
    /* 
    Diese Funktion führt das Newton'sche Näherungsverfahren durch
    */
    const int MaxIter = 100;
    
    double naeherung(int grad, double *koeff, double *koeffA, double xnull)
    {
      double xeins;
      int iter(0);
      do
      {
         double fxA;
         double fx;
         for(int i=1;i<=grad;++i)
         {
             fx  += koeff[i] * potenz(xnull,i);  //summiert f(x)
             fxA += koeffA[i] * potenz(xnull,i-1); //summiert f'(x)
         }
         xnull -= fx/fxA; //neuer Näherungswert
         ++iter;
      } while(fabs(xeins-xnull) > 1.0e-10 && iter < MaxIter);
      return xnull;
    }
    

    Als Ausgabe bekomme ich nun sogar einen "interessanten" wert für die oben angegebene Funktion. Nämlich -1.#IND aber wieso nicht -1.5??


Anmelden zum Antworten