Ungenauigkeit natürlicher Logarithmus



  • Hallo!

    Ich versuche, mich mit meinem Programm an den Grenzwert der Ableitung von log(1.6) heranzutasten:

    double d(double x, int k, int fkt)
    {
        int i;
        double h=1;
        for(i=1;i<=k;i++) h=h/10;
    
        printf("h:%1.20f\n",h);
        printf("erst: %1.40f\n",fkt1(x+h));
        printf("zweit:%1.40f\n",fkt1(x));
    
        return (fkt1(x+h)-fkt1(x))/h;
    }
    
    double fkt1(double x)
    {
        return log(x);
    }
    
    int main()
    {
        int i;
    
        for(i=1;i<=20;i++)
        {
            printf("%i: ",i);
            printf("d: %1.40f\n\n",d(1.6,i,1));
        }
    
        getch();
        return 0;
    }
    

    Das Problem ist, dass ab k=15 fkt1(x+h) genau gleich fkt1(x) ist, es scheint also, dass log aus der math.h nur auf 14 Nachkommastellen genau den Logarithmus berechnet. Ich brauche aber 20 Nachkommastellen Genauigkeit. Hat da jemand eine Idee? (fkt wird später benutzt, um diesen Wert für andere Funktionen berechnen zu können)

    Gruß


  • Mod

    Du kommst hier an die Genauigkeitsgrenze des Fließkommatyps double. Du wirst wohl eine Bibliothek benutzen müssen die quadruple-precision oder gar arbitrary-precision arithmetic erlaubt.

    Aber: Denk nochmal nach! Brauchst du das wirklich? Ganz sicher? Ganz ganz sicher? Und wenn ich nachgucke?



  • Du solltest dich auch mal mit der float.h auseinander setzen.
    Und lass dir doch auch mal x+h ausgeben.



  • Es gibt mit C89 auch den Typ long double, der ist u.U. "genauer" als double, vielleicht reicht der Typ für dich auf deinem System ja schon aus.
    Ab C99 gibt es auch "passende" Bibliotheksfunktionen für long double (und nicht nur für double), u.a. für dich logl:

    http://ideone.com/OpGrL



  • Danke erstmal für die Antworte. Ich brauche die 20 Stellen auf jeden Fall. Logl führt bei mir dazu, dass ich eine komische Ausgabe bekomme (auch mit dem von Wutz geposteten code):

    1: h:0.10000000000000000000
    erst: -1718026208.0000000000000000000000000000000000000000
    zweit:-859045856.0000000000000000000000000000000000000000
    d: -8589803520.0000000000000000000000000000000000000000
    
    2: h:0.01000000000000000000
    erst: 1000000000.0000000000000000000000000000000000000001
    zweit:-800000000.0000000000000000000000000000000000000001
    d: 200000000000.0000000000000000000000000000000000000001
    
    3: h:0.00100000000000000000
    erst: 1000000000.0000000000000000000000000000000000000001
    zweit:-800000000.0000000000000000000000000000000000000001
    d: 2000000000000.0000000000000000000000000000000000000001
    
    [...]
    


  • Bist du dir sicher, dass du richtig abgetippt hast?
    Der Compiler muss im C99 konformen Modus laufen (und natürlich die math-Lib richtig einbinden).



  • Edit: Compilerprobleme haben sich erledigt, hatte das c99 flag vergessen.
    Allerdings sind die letzten 4-5 durchläufe (15-20) immernoch "komisch" (wie auch bei dem von Wutz geposteten Link zu sehen). Woran kann das liegen?



  • Im Umgang mit Fließkommaartihmetik immer zu bedenken: Auslöschung. Du nimmst die Differenz zweier fast genau gleicher Zahlen - am Ende sogar genau gleicher Zahlen - und säbelst dir damit alle signifikanten Stellen weg.

    Warum machst du das eigentlich nicht symbolisch? Die Ableitung von ln(x) nach x ist 1/x.



  • Mir ist klar, dass ich da auch über die eigentliche Ableitung rangehen kann. Ich wollte ausprobieren, wie nah ich über die Approximierung an den tatsächlichen Wert herankomme, da muss ich mich dann wohl mit 15 Nachkommastellen zufrieden geben. Danke für eure Hilfe!



  • Das interessiert mich jetzt - an welcher Stelle bist du mit einem asymmetrischen Differenzenquotienten auf 15 Stellen genau an 0.625 herangekommen?

    Du hast zwei entgegengesetze Ungenauigkeitsquellen - wenn du das Epsilon zu klein wählst, säbelst du dir die signifikanten Stellen weg, und wenn du es zu groß wählst, wird der Differenzenquotient ungenauer. 15 Stellen Genauigkeit dürften (ohne viel Glück) weder mit double noch mit long double drin sein. Verlässlich machbar dürften geschätzt 7-8 (double) oder 9-10 (long double) sein, wenn das Epsilon perfekt gewählt ist, und die Wahl ist auch nicht ganz trivial.


  • Mod

    seldon schrieb:

    Das interessiert mich jetzt - an welcher Stelle bist du mit einem asymmetrischen Differenzenquotienten auf 15 Stellen genau an 0.625 herangekommen?

    +1

    Und ich muss auch noch nachtragen:

    SeppJ schrieb:

    Aber: Denk nochmal nach! Brauchst du das [die 20 Stellen Genauigkeit] wirklich? Ganz sicher? Ganz ganz sicher? Und wenn ich nachgucke?

    blstks schrieb:

    Danke erstmal für die Antworte. Ich brauche die 20 Stellen auf jeden Fall.

    Dann schieß doch mal bitte los, wozu man 20 Stellen auf jeden Fall braucht. Vor allem, da es nun anscheinend ja doch nicht so dringend war.



  • Die 20 Nachkommastellen waren so in der Aufgabenstellung gefordert (bzw. h=10^-20). Bis h=10^-15 habe ich "gute" Werte, danach geht es den Bach runter:

    1 0.60624621816434842594
    2 0.62305497506360742069
    3 0.62480476884208043117
    4 0.62498046956376419712
    5 0.62499804688313960471
    6 0.62499980468759389936
    7 0.62499998046845186775
    8 0.62499999805014534732
    9 0.62499999980655286674
    10 0.62500000021312868142
    11 0.62499999750262325021
    12 0.62499999750262325021
    13 0.62499972645208012883
    14 0.62500189485642509984
    15 0.62496123727495689343
    16 0.62477150189477193015
    17 0.62341624917916504961
    18 0.59631119486702743876
    19 0.54210108624275221706
    20 0.00000000000000000000

    Ich will da aber jetzt auch nicht auf Biegen und Brechen mehr Stellen erzwingen.


Anmelden zum Antworten