// Musterlösung der Aufgabe 1 des Übungsblattes Nr.7

#include <iostream>                                      // Ein- und Ausgabebibliothek
#include <cmath>                                         // Bibliothek für mathematisches (e-Funktion, Betrag, ...)

double f(double x) {                                     // Deklaration und Definition der Funktion f(x)
    double wert;                                         // Lokale double-Variable (nur im Bereich der Funktion gültig)
    wert = exp(x) - 20;                                  // Eigentliche Definition der Funktion
    return wert;                                         // Rueckgabewert der Funktion f(x)
}                                                        // Ende der Funktion f(x)

double f_strich_analyt(double x) {                       // Deklaration und Definition der Funktion f(x)
    double wert;                                         // Lokale double-Variable (nur im Bereich der Funktion gültig)
    wert = exp(x);                                       // Eigentliche Definition der Funktion
    return wert;                                         // Rueckgabewert der Funktion f(x)
}                                                        // Ende der Funktion f(x)

int main(){                                              // Hauptfunktion
    double p[3] = {2, 2, 2};                             // Deklaration des approximierten x-Wertes der Nullstelle und Start-Initialisierung
    const int N=10;                                      // Anzahl der Iterationen in der Newton-Raphson Methode
    double h = 0.1;                                      // Aequidistanter Abstand zwischen den x-Werten die zur numerischen Differentation benutzt werden
    const double p_null = log(20);
    
    // Beschreibung der ausgegebenen Groessen
    printf("# 0: Index i der Iteration i \n# 1: Approximierter Wert der Nullstelle p_i \n");
    printf("# 2: Dreipunkte-Mittelpunkt-Formel \n# 3: Fuenfpunkte-Mittelpunkt-Formel \n");
    printf("# 4: Relativer Fehler zum wirklichen Wert |(p-p_0)/p| \n# 5: Relativer Fehler zum wirklichen Wert |(p-p_1)/p| \n");
    printf("# 6: Relativer Fehler zum wirklichen Wert |(p-p_2)/p| \n");
    
    for(int i=0; i<N; ++i){                                                                       // For-Schleife der Newton-Raphson Methode
        printf("%3d %20.14f %20.14f %20.14f %20.14f %20.14f %20.14f \n",i, p[0], p[1], p[2], fabs((p_null-p[0])/p_null), fabs((p_null-p[1])/p_null), fabs((p_null-p[2])/p_null)); 
        
        p[0] = p[0] - f(p[0])/f_strich_analyt(p[0]);                                              // Newton-Raphson Methode mit analytischer Ableitung f'(x)
        p[1] = p[1] - f(p[1])/( (f(p[1]+h) - f(p[1]-h))/(2*h) );                                  // Newton-Raphson Methode, Dreipunkte-Mittelpunkt-Formel fuer f'
        p[2] = p[2] - f(p[2])/( (f(p[2]-2*h) - 8*f(p[2]-h) + 8*f(p[2]+h) - f(p[2]+2*h))/(12*h) ); // Newton-Raphson Methode, Fuenfpunkte-Mittelpunkt-Formel fuer f'
    }                                                                                             // Ende der For-Schleife der Newton-Raphson Methode
    printf("# Wirklicher Wert der Nullstelle: %20.14f \n", p_null);  
}
