Funktion auf mehrere dateien verpacken- wo fehler?



  • Kontrollier mal die Anzahl der Parameter von naeherung bei Deklaration und bei Anwendung.
    Bei Potenz muß der zweite Parameter (Exponent) übrigens int sein sonst macht deine Schleife keinen Sinn.
    Ansonsten schau dir mal pow aus der cmath an.



  • Du hast anscheinend einen Parameter vergessen (und irgendwo in deinen Headern findet der Compiler noch die 3-Parameter-Version), als du die Funktion naeherung() aufgerufen hast - richtig lautet das "naeherung(grad, koeff, koeffA, xnull);"

    (PS: Und die Funktion sollte eigentlich auch die berechnete Nullstelle zurückgeben)



  • bei der potenzierfunktion sag ich ja return be;
    wie kann ich diesen wert nun in den anderen funktionen verwenden?
    einfach be als variable nutze?

    Was ist denn pow? Wo kann man die Inhalte der cmath und allen anderen bibliotheken einsehen?
    ---
    Ich habe die Parameter nun angepasst und folgende änderung vorgenommen:
    naeherung.cpp:

    //Funktion zum Nähern
        naeherung(grad, koeff, koeffA, xnull);
    
        cout << fxAz <<;
    

    näherungsverfahren.cpp:

    #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 fx[grad];
           double fxA[grad];
           double fxz;
           double fxAz;
           double fxzz;
           double xeins;
           for (int i=0;i<grad;i++)
           {
           potenz(xnull, grad);
           fxA[i]=koeffA[i]*be;
           fxAz+=fxA[i];
           }
           return fxAz;
    }
    

    Aber ich kann trotzdem die Variable fxAz nicht ausgeben, was ich ja oben mit cout << fxAz <<; versuche...



  • t1m0n schrieb:

    bei der potenzierfunktion sag ich ja return be;
    wie kann ich diesen wert nun in den anderen funktionen verwenden?
    einfach be als variable nutze?

    Indem du das Ergebnis einer Variablen zuweist:

    double xn=potenz(x,n);
    

    (btw stimmt was nicht mit der Definition - der Header sagt "void potenz(...)", die Implementation verwendet "double potenz(...)")

    PS: Die Informationen zur Standard-Bibliothek findest du z.B. in den Manuals deines Compilers oder unter http://www.cppreference.com



  • Ausgabe bitte so

    cout << naeherung(grad, koeff, koeffA, xnull);
    

    Schau dir bitte ein Tutorial zu Funktionen an.
    z.Bsp. hier
    http://www.volkard.de/vcppkold/funktionen.html
    oder hier
    http://tutorial.schornboeck.net/funktionen2.htm
    oder...



  • Ich habs nun etwas merkwürdiger gemacht:

    double naeherung(int grad, double *koeff, double *koeffA, double xnull)
    {
           double fx[grad];
           double fxA[grad];
           double fxz;
           double fxAz;
           double fxzz;
           double xeins;
           for (int i=0;i<grad;i++)
           {
           fxA[i]=koeffA[i]*potenz(xnull, grad);
           fxAz+=fxA[i];
           }
           return fxAz;
    }
    

    Dann hab ich in der naeherung.cpp

    cout << naeherung(grad, koeff, koeffA, xnull);
    

    gemacht.
    Nun klappt alles soweit aber ich habe einen logischen fehler drinne (so heißt das doch oder?)
    Laut meinen Berechnungen müsste ich 14 herausbekommen, bekomme aber 28...
    Kennt sich jemand mit dem newton'schen näherungsverfahren aus udn kann mir da sagen was ich falsch habe?
    ---Aktuell sieht alles so aus:---

    naeherung.cpp:

    #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];
        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;
    }
    

    ableitung.h:

    double ableitung(int grad, double *koeff, double *koeffA);
    double potenz(double b, int e);
    double naeherung(int grad, double *koeff, double *koeffA, double xnull);
    

    ableitung.cpp:
    #include <iostream>
    #include "ableitung.h"
    using namespace std;
    /*
    Diese Funktion führt die eigentliche Ableitung durch.
    Es müssen hier zwei Parameter übergeben werden:
    Der Grad der Funktion und die Koeffizienten.
    */
    double ableitung(int grad, double *koeff, double *koeffA)
    {
    int i;
    for(i=0;i<grad;i++)
    {
    koeffA[i]=(grad - i)*koeff[i];
    }
    return 0;
    }
    potenz.cpp:

    #include <iostream>
    using namespace std;
    double potenz(double b, int e)
    {
    
            int i;
            double be = b;
            for(i=0; i<e-1; i++)
            {
            be=b*be;
            }
            return be;
    }
    

    Naherung.cpp:

    #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 fx[grad];
           double fxA[grad];
           double fxz;
           double fxAz;
           double fxzz;
           double xeins;
           for (int i=0;i<grad;i++)
           {
           fxA[i]=koeffA[i]*potenz(xnull, grad);
           fxAz+=fxA[i];
           }
           return fxAz;
    }
    


  • Erstmal hast du da ein ganzes Paket überflüssiger Variablen drin.

    Zweitens solltest du lieber potenz(xnull,i) oder potenz(xnull,grad-i) verwenden (je nachdem, in welcher Reihenfolge die Koeffizienten in dem Vektor stehen).

    Und drittens bin ich mir nicht sicher, was du damit eigentlich berechnen willst - die Funktion hat nichts mit dem Newton-Verfahren zu tun, sondern berechnet lediglich f'(xnull) für deine "mögliche Nullstelle" xnull.



  • Desweiteren ist fxAz in der Funktion nicht initialisiert. Da kann also irgendwas drinstehen.
    Newton wäre doch
    x1 = x0 - f(x0)/f'(x0) (kenn mich mit LATEX leider nicht so aus)
    und das iterativ.



  • Braunstein schrieb:

    Desweiteren ist fxAz in der Funktion nicht initialisiert. Da kann also irgendwas drinstehen.
    Newton wäre doch
    x1 = x0 - f(x0)/f'(x0) (kenn mich mit LATEX leider nicht so aus)
    und das iterativ.

    ja genau, aber ich brauche ja erst die f'x und die fx für die berechnung. Und die müssen ja erstmal berechnet werden und das verscuhe ich gerade..



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


Anmelden zum Antworten