Ungenauigkeiten von double



  • Hi,
    wir haben eine Aufgabe bezüglich der Genauigkeit von double bekommen.
    Und zwar sollte man die harmonische Reihe von 1 bis 1Mio einmal beginnend mit 1 berechnen und einmal rückwärts, also beginnend mit 1/1Mio.

    Und dazu Unterschiede feststellen und erklären. Hier erst einmal die Quellcodes:

    /* reihe_v.c - harmonische Reihe vorwärts */
    
    #include <stdio.h>
    
    int main(){
        int k, i; 
        double summe=0.0;
    
        printf("Nat. Zahl eingeben: ");
        scanf("%d",&k);
    
        for(i=1; i<=k; i++){
            summe += 1/(double)i;
        }
        printf("harm. Reihe von n=1 bis k=%d: %.15lf", k, summe);
    
        return 0;
    }
    
    /* reihe_r.c - harmonische Reihe rückwärts */
    
    #include <stdio.h>
    
    int main(){
        int k, i; 
        double summe=0.0;
    
        printf("Nat. Zahl eingeben: ");
        scanf("%d",&k);
    
        for(i=k; i>=1; i--){
            summe += 1/(double)i;
        }
        printf("harm. Reihe von n=1 bis k=%d: %.15lf", k, summe);
    
        return 0;
    }
    

    Vorwärts ergibt sich 18.997896413847702, rückwärts 18.997896413853162.
    Hiinten fehlt es also an Genauigkeit. Double ist ja nur begrenzt genau, das ist mir klar. Aber ich verstehe nicht wieso da Unterschiede entstehen.
    Da ich in der Schleife immer nur 2 Werte addiere müsste das ja bedeuten, dass bei hinreichend großen k, also kleinen Zahlen gilt: (a+b)≠(b+a).

    Ist das tatsächlich so?

    Grüße Magnus


  • Mod

    Nein. Der Unterschied ist: Wenn du zum Beispiel eine Zahl hast, die auf 15 zählende Stellen genau ist (was ungefähr ein double ist), dann kannst du zu 1 nicht 10^-16 addieren, weil dann immer noch 1 rauskommt. Du kannst aber wunderbar 10^-16 + 10^-16 rechnen, da kommt dann auch genau das richtige Ergebnis 2*10^-16 raus.

    Das Problem was du hier siehst liegt also da dran, dass du bei der einen Methode am Ende große Zahlen und kleine Zahlen addierst. Dadurch kommt die Genauigkeit der kleinen Zahl nicht mehr zur Geltung, da alles nach den 15 zählenden Stellen der großen Zahl abgeschnitten wird. Wenn du hingegen anfängst, die kleinen Zahlen zu addieren, dann hat jede Rechnung ungefähr die vollen 15 Stellen Genauigkeit und wenn du bei den größeren Zahlen angekommen bist, dann ist die Gesamtsumme mittlerweile auch groß geworden, so dass auch diese Additionen mit hoher Genauigkeit ausgeführt werden.

    Verstanden?

    Wichtig ist dabei, dass der double intern ungefähr so dargestellt wird, als wäre er in wissenschaftlicher Schreibweise geschrieben. Es wird also nicht 0.003 gespeichert, sondern 3*10^-3. Und die Zahl, wo in meinem Beispiel die 3 steht, hat nur endliche Genauigkeit. Mal ganz vereinfacht gesagt, die Genauigkeit wäre drei Stellen:

    3*10^-3 = 3.00*10^-3
    3.00*10^-3 + 4*10^-4 = 3.40 *10^-3
    3.40*10^-3 + 5*10^-5 = 3.45 *10^-3
    3.45*10^-3 + 6*10^-6 ~ 3.46 *10^-3 Tja, und hier siehst du das Problem
    

    Dabei war es ganz egal, ob da nun immer 10^-3 bis 10^-6 oder 10^666 bis 10^663 oder 10^-50 bis 10^-53 stand, der absolute Wert ist egal, es kommt auf den relativen Unterschied an.



  • Klingt sehr einleuchtend.
    Hatte mir schon gedacht, dass meine Lösung so nicht stimmen kann.

    Vielen Dank für die schnelle Antwort 🙂


Anmelden zum Antworten