Musterlösung zum Übungsblatt Nr. 5

Musterlösung zur Aufgabe 1 (8 Punkte)

Das folgende C++ Programm basiert auf dem Programm Lagrange_Polynom_1.cpp. Der Kern-Algorithmus des Programms wurde jedoch in eine Funktion "void Lagrange_Poly( ... )" ausgelagert.

A5_1.cpp
// Musterlösung der Aufgabe 1 des Übungsblattes Nr.5
/* Die Berechnung des Lagrange Polynoms wurde in die
 * Funktion Lagrange_Poly( ... ) ausgelagert */
#include <iostream>                                                    // Ein- und Ausgabebibliothek

double f(double x){                                                    // Deklaration und Definition der Funktion f(x) die approximiert werden soll
    double wert;
    wert = 1.0/x;                                                      // Eigentliche Definition der Funktion
    return wert;                                                       // Rueckgabewert der Funktion f(x)
}                                                                      // Ende der Funktion f(x)

void Lagrange_Poly(double* points, int N_points, double a, double b, const unsigned int N_xp, double* xp, double* fp, double* Pfp){
    double dx = (b - a)/N_xp;                                          // Abstand dx zwischen den aequidistanten Punkten des x-Intervalls
    double x = a - dx;                                                 // Aktueller x-Wert
    double Lk;                                                         // Deklaration einer Variable, die fuer Zwischenrechnungen benoetigt wird
    
    for(int j = 0; j <= N_xp; ++j){                                    // For-Schleife die ueber die einzelnen Punkte des x-Intervalls geht
        x=x+dx;                                                        // Aktueller x-Wert
        xp[j]=x;                                                       // Eintrag des aktuellen x-Wertes in das x-Array
        fp[j]=f(x);                                                    // Eintrag des aktuellen f(x)-Wertes in das f(x)-Array
        
        Pfp[j]=0;                                                      // Initialisierung des j-ten Polynom-Arrays mit 0 (Wert beim Anfang der Summenbildung)
        for(int k = 0; k < N_points; ++k){                             // For-Schleife der Summation in der Lagrange Polynom Methode
            Lk=1;                                                      // Initialisierung der Produktvariable Lk mit 1 
            for(int i = 0; i < N_points; ++i){                         // For-Schleife der Produktbildung in der Lagrange Polynom Methode
                if(i != k){                                            // Die Produktbildung soll nur fuer (i ungleich k) erfolgen 
                    Lk = Lk * (x - points[i])/(points[k] - points[i]); // Berechnung der Lk-Werte in der Lagrange Polynom Methode
                }                                                      // Ende if-Bedingung
            }                                                          // Ende for-Schleife der Produktbildung
            Pfp[j] = Pfp[j] + f(points[k])*Lk;                         // Kern-Gleichung in der Lagrange Polynom Methode
        }                                                              // Ende for-Schleife der Summenbildung
    }                                                                  // Ende der for-Schleife ueber die einzelnen Punkte des x-Intervalls
}                                                                      // Ende der Funktion f(x)

int main(){                                                            // Hauptfunktion
    double points[] = { 2, 2.5, 4 };                                   // Deklaration und Initialisierung der Stützstellen als double-Array
    const unsigned int N_points = sizeof(points)/sizeof(points[0]);    // Anzahl der Punkte die zur Approximation verwendet werden 
    double plot_a=0.5;                                                 // Untergrenze des x-Intervalls in dem die Ergebnisse ausgegeben werden sollen
    double plot_b=6;                                                   // Obergrenze des x-Intervalls in dem die Ergebnisse ausgegeben werden sollen
    const unsigned int N_xp=300;                                       // Anzahl der Punkte in die das x-Intervall aufgeteilt wird
    double xp[N_xp+1];                                                 // Deklaration der x-Ausgabe-Punkte als double-Array
    double fp[N_xp+1];                                                 // Deklaration der f(x)-Ausgabe-Punkte als double-Array
    double Pfp[N_xp+1];                                                // Deklaration der Ausgabe-Punkte des approximierten Polynoms als double-Array

    printf("# x-Werte der %3d Stuetzstellen-Punkte: \n", N_points);    // Beschreibung der ausgegebenen Groessen
    for(int k = 0; k < N_points; ++k){                                 // For-Schleife der Ausgabe der Stuetzstellen x-Werte
        printf("%10.5f",points[k]);                                    // Ausgabe der Stuetzpunkte
    }                                                                  // Ende for-Schleife der Ausgabe
    printf("\n");                                                      // Zeilenumbruch
    
    printf("# 0: Index j \n# 1: x-Wert \n# 2: f(x)-Wert \n");          // Beschreibung der ausgegebenen Groessen
    printf("# 3: Approximierter Wert des Lagrange Polynoms P(x) \n");  // Beschreibung der ausgegebenen Groessen
    printf("# 4: Fehler zum wirklichen Wert f(x)-P(x) \n");            // Beschreibung der ausgegebenen Groessen
    
    Lagrange_Poly(points,N_points,plot_a,plot_b,N_xp,xp,fp,Pfp);       // Berechnung der Wertetabelle des Lagrange Polynoms
    
    for(int j = 0; j <= N_xp; ++j){                                                                  // For-Schleife der separaten Ausgabe der berechneten Werte
        printf("%3d %14.10f %14.10f %14.10f %14.10f \n",j, xp[j], fp[j], Pfp[j], (fp[j] - Pfp[j]));  // Ausgabe der berechneten Werte
    }                                                                                                // Ende for-Schleife der Ausgabe
}                                                                                                    // Ende der Hauptfunktion

Die ersten fünf Einträge in der Argumentenliste der Funktion werden bei ihrem Aufruf initialisiert und die darauf folgenden drei Argumente stellen die Zeiger auf die im Hauptprogramm deklarierten Arrays double xp[N_xp+1], double fp[N_xp+1] und double Pfp[N_xp+1] dar. Es wurde das Programm mit den Vorgaben ($f(x)=1/x$ und $\vec{x}=\left( 2, 2.5, 4 \right)$) getestet und das im Terminal ausgegebene Ergebnis entsprach exakt den zuvor berechneten Werten. Nun wurde das Lagrange Polynom vom Grade $n=8$ im Teilintervall $[a,b]=[0.91,9.07]$ mit $f(x) = 10 \, e^{-x/5} \cdot \hbox{sin}(3 \, x)$ und $\vec{x}=\left( 1,2,3,4,5,6,7,8,9 \right)$ berechnet (siehe A5_1a.cpp). Die nebenstehende Abbildung visualisiert die Ergebnisse des Programms (das zugehörige Python Skript findet man unter PythonPlot_A5_1.py).




Musterlösung zur Aufgabe 2 (6 Punkte)

Gegeben seien die folgenden x- und y-Werte der Stützstellen: $\vec{x} = \left( 2, 10.1, 15, 20, 40, 60, 90 \right)$ und $\vec{y} = \left( 2.1, 41, 43, 40.2, 12, 5, 17.5 \right)$. Das folgende C++ Programm berechnet das Lagrange Polynom $P_6(x)$ im Teilintervall $[a,b]=[0,100]$. Als Vorlage des Programms wurde bereits das in der vorigen Aufgabe vorgestellte Musterlösungsprogramm A5_1.cpp verwendet, bei welchem der Kern-Algorithmus der Lagrange Polynom Methode in eine Funktion ausgelagert wurde. Die wesentliche Abänderung wurde in der Kern-Gleichung der Lagrange Polynom Methode gemacht (Anweisung: "Pfp[j] = Pfp[j] + points_y[k]*Lk;") bei der nun nicht die "f(points[k])"-Werte, sondern die "points_y[k]"-Werte stehen.

A5_2.cpp
// Musterlösung der Aufgabe 2 des Übungsblattes Nr.5
/* Die Berechnung des Lagrange Polynoms wurde in die
 * Funktion Lagrange_Poly( ... ) ausgelagert 
 * es wurde keine Funktion f(x) definiert, sondern 
 * zusätzlich zu den x-Werten der Stützstellen
 * wurden auch die y-Werte angegeben
 */
#include <iostream>                                                    // Ein- und Ausgabebibliothek

void Lagrange_Poly(double* points, double* points_y, int N_points, double a, double b, const unsigned int N_xp, double* xp, double* Pfp){
    double dx = (b - a)/N_xp;                                          // Abstand dx zwischen den aequidistanten Punkten des x-Intervalls
    double x = a - dx;                                                 // Aktueller x-Wert
    double Lk;                                                         // Deklaration einer Variable, die fuer Zwischenrechnungen benoetigt wird
    
    for(int j = 0; j <= N_xp; ++j){                                    // For-Schleife die ueber die einzelnen Punkte des x-Intervalls geht
        x=x+dx;                                                        // Aktueller x-Wert
        xp[j]=x;                                                       // Eintrag des aktuellen x-Wertes in das x-Array
        
        Pfp[j]=0;                                                      // Initialisierung des j-ten Polynom-Arrays mit 0 (Wert beim Anfang der Summenbildung)
        for(int k = 0; k < N_points; ++k){                             // For-Schleife der Summation in der Lagrange Polynom Methode
            Lk=1;                                                      // Initialisierung der Produktvariable Lk mit 1 
            for(int i = 0; i < N_points; ++i){                         // For-Schleife der Produktbildung in der Lagrange Polynom Methode
                if(i != k){                                            // Die Produktbildung soll nur fuer (i ungleich k) erfolgen 
                    Lk = Lk * (x - points[i])/(points[k] - points[i]); // Berechnung der Lk-Werte in der Lagrange Polynom Methode
                }                                                      // Ende if-Bedingung
            }                                                          // Ende for-Schleife der Produktbildung
            Pfp[j] = Pfp[j] + points_y[k]*Lk;                          // Kern-Gleichung in der Lagrange Polynom Methode
        }                                                              // Ende for-Schleife der Summenbildung
    }                                                                  // Ende der for-Schleife ueber die einzelnen Punkte des x-Intervalls
}                                                                      // Ende der Funktion Lagrange_Poly(...)

int main(){                                                            // Hauptfunktion
    double points[] = { 2, 10.1, 15, 20, 40, 60, 90 };                 // Deklaration und Initialisierung der Stützstellen als double-Array
    double points_y[] = { 2.1, 41, 43, 40.2, 12, 5, 17.5 };            // Deklaration und Initialisierung der Stützstellen als double-Array
    const unsigned int N_points = sizeof(points)/sizeof(points[0]);    // Anzahl der Punkte die zur Approximation verwendet werden 
    double plot_a=1;                                                   // Untergrenze des x-Intervalls in dem die Ergebnisse ausgegeben werden sollen
    double plot_b=90.7;                                                // Obergrenze des x-Intervalls in dem die Ergebnisse ausgegeben werden sollen
    const unsigned int N_xp=500;                                       // Anzahl der Punkte in die das x-Intervall aufgeteilt wird
    double xp[N_xp+1];                                                 // Deklaration der x-Ausgabe-Punkte als double-Array
    double Pfp[N_xp+1];                                                // Deklaration der Ausgabe-Punkte des approximierten Polynoms als double-Array

    printf("# x-Werte der %3d Stuetzstellen-Punkte: \n", N_points);    // Beschreibung der ausgegebenen Groessen
    for(int k = 0; k < N_points; ++k){                                 // For-Schleife der Ausgabe der Stuetzstellen x-Werte
        printf("%10.5f",points[k]);                                    // Ausgabe der Stuetzpunkte
    }                                                                  // Ende for-Schleife der Ausgabe
    printf("\n");                                                      // Zeilenumbruch
    
    printf("# y-Werte der %3d Stuetzstellen-Punkte: \n", N_points);    // Beschreibung der ausgegebenen Groessen
    for(int k = 0; k < N_points; ++k){                                 // For-Schleife der Ausgabe der Stuetzstellen y-Werte
        printf("%10.5f",points_y[k]);                                  // Ausgabe der Stuetzpunkte
    }                                                                  // Ende for-Schleife der Ausgabe
    printf("\n");                                                      // Zeilenumbruch
    
    printf("# 0: Index j \n# 1: x-Wert \n");                           // Beschreibung der ausgegebenen Groessen
    printf("# 2: Approximierter Wert des Lagrange Polynoms P(x) \n");  // Beschreibung der ausgegebenen Groessen
    
    Lagrange_Poly(points,points_y,N_points,plot_a,plot_b,N_xp,xp,Pfp); // Berechnung der Wertetabelle des Lagrange Polynoms
    
    for(int j = 0; j <= N_xp; ++j){                                    // For-Schleife der separaten Ausgabe der berechneten Werte
        printf("%3d %14.10f %14.10f \n",j, xp[j], Pfp[j]);             // Ausgabe der berechneten Werte
    }                                                                  // Ende for-Schleife der Ausgabe
}                                                                      // Ende der Hauptfunktion

Die nebenstehende Abbildung visualisiert die Ergebnisse des Programms (das zugehörige Python Skript findet man unter PythonPlot_A5_2.py).



Musterlösung zur Aufgabe 3 (6 Punkte)

Im unten dargestellten C++ Programm wurde zwei Tausch-Funktionen definiert, wobei nur eine von diesen eine wirkliche Vertauschung der Zahlenwerte von a und b realisiert. Die Terminalausgabe des Programms ist in der oberen rechten Abbildung zu sehen. Die Funktion "void Tausche_ab_FALSCH(double a, double b){ ... }" ist ein FALSCHER Versuch einer Tauschfunktion! Die Funktion benutzt in der Argumentenliste direkt die double-Variablen double a und double b. Der Gültigkeitsbereich dieser lokalen Variablen ist jedoch lediglich auf den 'Block von Anweisungen' der Funktion beschränkt und kann deshalb die Werte der Variablen a und b der main()-Funktion nicht verändern bzw. austauschen. Die Funktion "void Tausche_ab(double* pa, double* pb){ ... }" benutzt hingegen die Zeiger auf a und auf b in der Argumentenliste und kann somit auf die Werte vertauschen. Im Programm wurde zunächst die ursprünglichen initialisierten Werte der Variablen a und b ausgegeben, danach die falsche Tauschfunktion aufgerufen und erneut die aktuellen Werte von a und b im Terminal ausgegeben. Dann wurde die "richtige" Tauschfunktion ausgeführt und erneut der Wert der Variablen ausgegeben.

A5_3.cpp
// Musterlösung der Aufgabe 3 des Übungsblattes Nr.5 

#include <iostream>                            // Ein- und Ausgabebibliothek

// Tauschfunktion mit Argumentenliste von Zeigern auf a und b
void Tausche_ab(double* pa, double* pb){
        printf("Vertausche a mit b \n"); 
        double tmp = *(pa);                    // Speichert den Wert von a
        *(pa) = *(pb);                         // Schreibt den Wert von b in a
        *(pb) = tmp;                           // Schreibt den alten Wert von a in b
    }

// Tauschfunktion mit Argumentenliste von double Variablen a und b
// Problem: a und b sind lokale Variablen, die ihren Gueltigkeitsbereich 
// nur innerhalb des Anweisungsblockes der Funktion hat
void Tausche_ab_FALSCH(double a, double b){
        printf("Vertausche a mit b (aber FALSCH !) \n"); 
        double tmp = a;                        // Speichert den Wert von a
        a = b;                                 // Schreibt den Wert von b in a
        b = tmp;                               // Schreibt den alten Wert von a in b
    }
    
int main(){                                    // Hauptfunktion
    double a = 5.437;                          // Definition a
    double b = 1.234;                          // Definition b

    printf("a = %6.3f , b = %6.3f \n", a,b); 
    Tausche_ab_FALSCH(a,b);                    // führe falsche Tauschfunktion aus
    printf("a = %6.3f , b = %6.3f \n", a,b); 
    Tausche_ab(&a,&b);                         // führe richtige Tauschfunktion aus
    printf("a = %6.3f , b = %6.3f \n", a,b); 
}