Funktion auf mehrere dateien verpacken- wo fehler?



  • 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??



  • Davon ist nichts überflüssig
    1.
    int iter(0);
    Damit erzeuge ich eine int-Variable mit dem Namen iter und weise ihr 0 zu (als Initialisierung). Diese Variable zählt einfach die Anzahl der Iterationen mit. Wenn die Anzahl MaxIter erreicht wird abgebrochen, egal ob Konvergenz erreicht ist oder nicht.
    2.
    xeins=xnull;
    Du mußt dir doch den alten Wert merken sonst kannst du zum Schluß doch keine Differenz bilden (als Konvergenzkriterium).
    3.
    double fxA=0;
    Damit erzeuge ich eine double-Variable mit dem Namen fxA und weise ihr 0 zu (als Initialisierung). Da kommt der Wert der Ableitung rein.
    4.
    double fx = koeff[0];
    Damit erzeuge ich eine double-Variable mit dem Namen fx und weise ihr das erste Element des Koeff-Arrays zu (als Initialisierung). Da kommt der Funktionswert rein.
    Nun schau mal mit dem Debugger rein. Wichtig ist hier vor allem die Belegung der Arrays (stimmt die Ableitung?) sowie die Funktion Potenz.



  • Wieso initialisierst du so:
    int

    iter(0);
    

    ?? geht doch auch int

    iter=0;
    

    ?
    Desweiteren vermute ich nicht das der Fehler bei mir liegt, weil ich mir ziemlig sicher bin, hab die Funktionen mehrfach getestet bevor ich sie verwende.
    Eher vermute ich hier den Fehler:

    fx  += koeff[i] * potenz(xnull,i);
    

    Grund: Der erste Koeffizient wird, weil du im ersten Fall mit i 0 übergibst falsch potenziert. Der erste Koeffizient müsste mit dem höchsten Exponenten potenziert werden, sprich grad! Richtig? Ich probiere mal...

    Läuft aufs gleiche hinaus.
    Ich verstehe deine Punkte 3 und 4 nicht wozu das Not tut. 1 und 2 jedoch wohl bzw. 1 mit Einschrenkung.

    Der Debugger findet nichts.. keine Warnung.. nichts..



  • So nun zu Potenz. Die Funktion ist auch nicht ganz korrekt. Es fehlt eine Abfrage für e=0;

    double potenz(double b, int e)
    {
       if( i==0 ) return 1.0;
       if( i==1 ) return b;
       double be = b;
       for(int i=0; i<e-1; i++)
       {
         be *= b;
       }
       return be;
    }
    

    Für negative e müßte man auch noch eine Sonderbehandlung einführen.
    Ansonsten nimm statt deiner eigenen Potenz pow.
    Bsp.

    fx  += koeff[i] * pow(xnull,i);
    


  • Ok naeherung ist auch falsch, weil es davon ausgeht, dass die Koeffizienten aufsteigend sortiert sind, es ist aber absteigend.

    double fx = koeff[grad];
    for(int i=grad;i<=1;--i)
    {
        fx  += koeff[i] * potenz(xnull,i);  //summiert f(x)
        fxA += koeffA[i] * potenz(xnull,i-1); //summiert f'(x)
    }
    


  • Hallo,

    Ich hab gerade erst deinen letzten post gelesen.
    Ob du iter mit int iter = 0; oder int iter(0); initialisierst ist egal.
    bzgl. Punkte 3 und 4. Du addierst doch fx und fxA in der for-Schleife auf. Da müssen sie doch einen Anfangswert haben. Bei C++ sind die Variablen nicht automatisch 0 bei der Deklaration.



  • Braunstein schrieb:

    Ok naeherung ist auch falsch, weil es davon ausgeht, dass die Koeffizienten aufsteigend sortiert sind, es ist aber absteigend.

    double fx = koeff[grad];
    for(int i=grad;i<=1;--i)
    {
        fx  += koeff[i] * potenz(xnull,i);  //summiert f(x)
        fxA += koeffA[i] * potenz(xnull,i-1); //summiert f'(x)
    }
    

    Mit den Koeffizienten ist das nicht ganz richtig gesagt. Ich gehe nur davon aus, das die Koeffizienten in Abhängigkeit zu den Exponenten absteigend eingegeben werden! Desweiteren stimme ich

    fx  += koeff[i] * potenz(xnull,i);  //summiert f(x)
    

    Ja nicht ganz zu weil es die Variable grad sein muss und nicht i die ausgewertet wird, da ja absteigend.
    Und mit ^0 meintest du bestimmt, das 2^0 nicht 1 bei mir ergeben richtig?

    Nun steht bei mir folgendes:

    #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] * pow(xnull,grad);  //summiert f(x)
             fxA += koeffA[i] * pow(xnull,grad-1); //summiert f'(x)
         }
         xnull -= fx/fxA; //neuer Näherungswert
         ++iter;
      } while(fabs(xeins-xnull) > 1.0e-10 && iter < MaxIter);
      return xnull;
    }
    

    Aber das Ergebnis ist immernoch verwirrend!

    Und was ist mit dem i=1 in der for-Schleife? i=0 wäre doch sinnvoller nicht war?



  • Uups? Ist natürlich Quatsch was ich da geschrieben hab
    So ist es besser.

    double fx = koeff[grad];
    for(int i=grad;i<=1;--i)
    {
        fx  += koeff[grad - i] * potenz(xnull,i);  //summiert f(x)
        fxA += koeffA[grad - i] * potenz(xnull,i-1); //summiert f'(x)
    }
    


  • Der Debugger zeigte hier einen Fehler:

    fx  += koeff[grad - i] * potenz(xnull,i);  //summiert f(x)
    

    Ich habe nun auf meine eigene potenz(); verzichtet und verwende nun pow(); aus cmath. Habs dementsprechend auch angepasst und somit den erwähnten Fehler behoben.
    Nun gibt er -1,#INF wieder aus. Ich dachte das liegt an dieser Zeile:

    for(int i=grad;i<=1;--i)
    

    Habe deshalb die Bedingung auf <=0 angepasst aber komme auch hier zum gleichen Ergebnis. -> -1,#INF
    Nicht ganz der gewünschte Wert!

    Kurze Frage nebenbei: Kann ich mir eigentlich die standartbibliotheken angucken irgendwo? Möchte gerne wissen wie die pow() aufegbaut ist. Suche auch noch ein gutes Buch das ALLE Standartfunktionen erklärt. Jemand einen Tipp?



  • fx  += koeff[i] * pow(xnull,grad);  //summiert f(x)
    fxA += koeffA[i] * pow(xnull,grad-1);
    

    Das ist Unsinn. Du hast doch ein Polynom. Hier wäre doch jeder Exponent gleich.

    Bei grad=3 würde das so aussehen.
    f(x) = koeff[grad] * x^grad + koeff[grad-1] * x^grad + ... + koeff[0] * x^grad

    das Ganze muß doch aber so aussehen
    f(x) = koeff[grad] * x^grad + koeff[grad-1] * x^(grad-1) + ... + koeff[0] * x^0

    die Ableitung dann so
    f'(x) = koeff[grad] * grad * x^(grad-1) + koeff[grad-1] * (grad-1) * x^(grad-2) + ... + koeff[1] * x^0

    CStoll hat dir doch den Link hier gegeben
    http://www.cppreference.com
    da stehen doch die Standardbibliotheken.
    und darin steht auch pow
    http://www.cppreference.com/stdmath/pow.html



  • for(int i=grad;i<=0;--i)
    

    Versteh ich beispielsweise auch nicht weil i=grad schwachsinnig ist, sondern i=0 sinnvoller...

    for(int i=0;i<=grad;i++)
    

    wäre für mich erstmal sinnvoller
    mhm.. und wie sollte es dann richtig aussehen?
    Für sinnvoller halte ich folgendes:

    #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[grad];
         for(int i=0;i<=grad;i++)
         {
          fx  += koeff[grad - i] * pow(xnull,grad);  //summiert f(x)
          fxA += koeffA[grad - i] * pow(xnull,grad-1); //summiert f'(x)
         }
         xnull -= fx/fxA; //neuer Näherungswert
         ++iter;
      } while(fabs(xeins-xnull) > 1.0e-10 && iter < MaxIter);
      return xnull;
    }
    

    Nun bekomme ich nämlich auch ein Ergebnis: 1.31624 für die oben genannte Funktion. Dies entspricht aber dennoch keiner wahren Nullstelle dieser funktion 😞
    -1.5 und 0 sind die Nullstellen bei dieser Funktion:
    grad=2, koeff1=2, koeff2=3, xnull=-2



  • Wenn dann bitte schön so

    double fx = koeff[grad];
    for(int i=0;i<grad;++i)
    {
        fx  += koeff[i] * pow(xnull,grad - i);  //summiert f(x)
        fxA += koeffA[i] * pow(xnull,grad - i - 1); //summiert f'(x)
    }
    

    Bitte lies auch nochmal meinen vorigen Post.



  • Braunstein schrieb:

    Wenn dann bitte schön so

    double fx = koeff[grad];
    for(int i=0;i<grad;++i)
    {
        fx  += koeff[i] * pow(xnull,grad - i);  //summiert f(x)
        fxA += koeffA[i] * pow(xnull,grad - i - 1); //summiert f'(x)
    }
    

    Bitte lies auch nochmal meinen vorigen Post.

    Ja, aber dann bekommen wir wieder -1,#IND
    Liegt das daran, dass die Größe des Double-Datentyps überschritten wird?



  • Wie deklarierst du eigentlich koeff und koeffA?
    Wenn du grad eingeben läßt, sollte es etwa so aussehen.

    double* koeff = new double[grad+1]; // du hast ja grad+1 Koeffizienten
    double* koeffA = new double[grad]; // kann ja eins kleiner sein
    // ganz zum Schluß dann noch
    delete[] koeff;
    delete[] koeffA;
    

    Bei vorgegebenen konstanten grad reicht dann auch sowas

    double koeff[grad+1];
    double koeffA[grad];
    


  • Bei vorgegebenen konstanten grad reicht dann auch sowas

    Was heißt das? Wozu delete? Die koeff wird bereits in der naeherung.cpp dekleriert. Das ist die datei über die die Werte eingegeben werden:

    #include <iostream>
    #include <conio.h>
    #include "ableitung.h"
    using namespace std;
    /*Diese Funktion fragt lediglich alle Einzugebenen Daten ab.
    grad steht für den Grad der Funktion.
    koeff reserviert den Platz für die Koeffizienten, die Anzahl ist ja vom Grad abhängig.
    xnull steht für den Startwert.
    */
    int main(void)
    {
        char r;
        int grad;
        double koeff[grad];
    
        //Die Eingabe des Grades und der Koeffizienten kann ggf. wiederholt werden
        do
        {
         int i;
         cout << "Bitte geben Sie den Grad der Funktion ein: ";
         cin >> grad;
         cout << "Bitte geben Sie jetzt die Koeffizienten ein (absteigende Reihenfolge der Exponenten und 0 beachten): " << endl;
    
         //Eingabe der Koeffizienten, bedingt durch den Grad der Funktion
         for(i=0;i<grad;i++)
         {
          cin >> koeff[i];
         }
         cout << "Ist das Ihre Funktionsgleichung: ";
    
         //Ausgabe der Koeffizienten, bedingt durch den Grad der Funktion
         for (i=0;i<grad;i++)
         { 
           cout << "+" << koeff[i] << "x^" << grad - i; 
         }
         cout << "? Wenn ja geben sie j ein und bestaetigen Sie mit Enter. Anderfalls geben Sie bitte n ein und bestaetigen dies: ";
         cin >> r;
        }while(r=='n');
        //Wenn die ausgegebene Funktionsgleichung mit der des Benutzers übereinstimmt geht es hier weiter, anderfalls wird die Eingabe wiederholt.
    
        //Eingabe des Startwertes
        double xnull;
        cout << "Bitte geben Sie den Startwert x0 fuer die Naeherung an: ";
        cin >> xnull;
    
        //Funktion zum Ableiten
        double koeffA[grad+1];
        ableitung(grad, koeff, koeffA);
    
        //Ausgabe der abgeleiteten Koeffizienten
        cout << endl << "Die abgeleiteten Koeffizienten sind: ";
        for(int i=0;i<grad;i++)
        {
         koeffA[i]=(grad - i)*koeff[i];
         cout << koeffA[i] << ", ";
        }
    
        //Funktion zum Nähern
        cout << naeherung(grad, koeff, koeffA, xnull);
        /*
        char re;
        do
        {
         cout << endl << "Moechten Sie die Naeherung erneut durchfuehren um ein exakteres Ergebnis zu erhalten? Wenn ja geben sie j ein und bestaetigen Sie mit Enter. Anderfalls geben Sie bitte n ein und bestaetigen dies: ";
         cin >> re;
        }while(re=='j');
        */
        getch();
        return 0;
    }
    

    Ich habe nun grad+1 in der Definition nun mal getestet, bekomme aber auch wieder -1.#IND ausgegeben. Die Änderung siehst du hier:

    //Funktion zum Ableiten
        double koeffA[grad+1];
    

    vorher nur grad! Die Dekleration kann aber nur von hier erfolgen weil die Koeffizienten übergeben werden.


Anmelden zum Antworten