Harmonische Reihe



  • Warum endet das folgende Programm in einer Endlosschleife? Normalerweise müsste es die harmonische Reihe 1 + 1/2 + 1/3 + 1/4 usw. berechnen und angeben können, nach wieviel Reihengliedern bzw. Sekunden die Reihensumme die Werte 1, 2, 3, 4 usw. überschreitet. Hat hier jemand eine Idee?

    #include <stdio.h>
        #include <time.h>
        #define  grenze     10.
        #define  zaehler     1.
    
        main ()
        {
          long    nenner = 1                              ;
          double  summe  = 0. , zielsumme = 1. , dnenner  ;
    
          while (zielsumme <= grenze)
            {
              dnenner = (double) nenner ;
              summe = zaehler / dnenner ;
              if (summe >= zielsumme)
                {
                  printf ("Summe %8.2lf erreicht mit %10ld Summanden" ,
                                 summe , nenner)   ;
                  printf ("    Zeit:%8.3lf Sekunden\n" ,
                               (double) clock () / CLOCKS_PER_SEC) ;
                  zielsumme += 1. ;
                }
              nenner++  ;
            }
    
          system ("PAUSE") ; 
          return 0 ;
    

    Neben dem obligatorischen Hello, World ist das mein erstes C(++)-Programm. Ich kann mir vorstellen, dass der Fehler irgendwie mit dem Casten der Variablen zusammenhängt.

    Ah ja, da wäre noch eine Kleinigkeit:

    Ich habe folgendes schrieben:

    dnenner = (double) nenner ;
              summe = zaehler / dnenner ;
    

    Könnte man es auch auf nachfolgende Weise vereinfachen?

    summe = zaehler / (double) nenner ;
    

    Schon mal danke im Voraus! 😉



  • Du berechnest die Summe falsch. Eigentlich berechnest du nur jeden Summanden der Reihe einzeln. Zu einer Summe gehört, dass man auch irgendwo mal etwas addiert.



  • Tatsächlich... da hat ein "summe + " gefehlt. So sieht es richtig aus:

    #include <stdio.h>
        #include <time.h>
        #define  grenze     10.
        #define  zaehler     1.
    
        main ()
        {
          long    nenner = 1                              ;
          double  summe  = 0. , zielsumme = 1. , dnenner  ;
    
          while (zielsumme <= grenze)
            {
              dnenner = (double) nenner ;
              summe = summe + zaehler / dnenner ;
              if (summe >= zielsumme)
                {
                  printf ("Summe %8.2lf erreicht mit %10ld Summanden" ,
                                 summe , nenner)   ;
                  printf ("    Zeit:%8.3lf Sekunden\n" ,
                               (double) clock () / CLOCKS_PER_SEC) ;
                  zielsumme += 1. ;
                }
              nenner++  ;
            }
    
          system ("PAUSE") ; 
          return 0 ;
        }
    

    Thanks!



  • Hallo!

    Ich muss mal meinen Senf dazugeben. Auch wenn es scheinbar Dein zweites Programm ist, sollte man Dich auf ein paar Kleinigkeiten hinweisen:

    1.) C ode C++?
    Du hast den Beitrag ins C++-Forum gestellt, Dein Code sieht aber aus wie C. C++: cout statt printf, const statt #define...

    2.) ++ und +=:
    Du solltest statt var = var + 1 immer ++var benutzen. Wo es geht ist ++var auch var++ vorzuziehen. Ist vielleicht nur marginal, aber ++var ist schneller als var++ und viele Compiler optimieren das scheinbar nicht (lt. Scott Meyers).

    Satt summe = summe + ..... schreibst Du besser summe += ...., wie Du weiterunten mit der zielsumme gemacht hast.

    3.) system("PAUSE"):
    Wurden hier schon sehr viele Worte drüber verloren....

    4.) Numerische Stabilität
    Dein Algorithmus ist numerisch unstabil. Wenn Du eine zu hohe Grenze wählst, dann wird Dein Algo diese aufgrunde von Rundgsfehlern nicht erreichen und in einer Endlosschleife stecken bleiben.

    Du solltest auf jeden Fall überprüfen, ob sich Deine Summe verändert hat. Kurze Erklärung:
    große Zahl + sehr kleine Zahl = große Zahl für den PC. Aufgrund von Rundung werden die kleinen Summanden nicht beachtet...

    Sorry, dass ich gleich mit dem Ganzen auf Dich zustürze, aber ich denke, es ist besser früh Hinweise zu bekommen, als sich an einen nicht so guten Stil zu gewöhnen. Lass Dich davon nicht entmutigen!

    Grüße
    Richie



  • Richie_Gecco schrieb:

    2.) ++ und +=:
    Du solltest statt var = var + 1 immer ++var benutzen. Wo es geht ist ++var auch var++ vorzuziehen. Ist vielleicht nur marginal, aber ++var ist schneller als var++ und viele Compiler optimieren das scheinbar nicht (lt. Scott Meyers).

    bei elementaren typen ist das dem compiler egal. allenfalls passierte es mal, daß compiler echt gar nicht optimiert hatten, und da war für int dann sogar i++ schneller, wenn es darum ging, die parallelverarbeitung des prozessors besser oder schlechter auszunutzen. aber wie gesagt, heute ist ++i und i++ völlig gleich schnell für int, double und so. für selbstgebaute iteratoren ist ++i potentiell schneller und man sollte deshalb gleich immer ++i schreiben, damit man's so gewohnt ist.

    4.) Numerische Stabilität
    Dein Algorithmus ist numerisch unstabil. Wenn Du eine zu hohe Grenze wählst, dann wird Dein Algo diese aufgrunde von Rundgsfehlern nicht erreichen und in einer Endlosschleife stecken bleiben.

    mir fällt sofort ein, daß die summe von for(int i=1;i<=1000000;++i)s+=1.0/i; sich gar nicht so genau anfühlt, wie for(int i=1000000;i>=1;--i)s+=1.0/i;
    aber in dem fall, wo er feststellen will, bis wohin er aufsummieren muß, fällt mir nix ganz einfaches ein, um die sache stabiler zu machen.
    hast du ne idee?



  • volkard schrieb:

    Richie_Gecco schrieb:

    2.) ++ und +=:
    Du solltest statt var = var + 1 immer ++var benutzen. Wo es geht ist ++var auch var++ vorzuziehen. Ist vielleicht nur marginal, aber ++var ist schneller als var++ und viele Compiler optimieren das scheinbar nicht (lt. Scott Meyers).

    bei elementaren typen ist das dem compiler egal. allenfalls passierte es mal, daß compiler echt gar nicht optimiert hatten, und da war für int dann sogar i++ schneller, wenn es darum ging, die parallelverarbeitung des prozessors besser oder schlechter auszunutzen. aber wie gesagt, heute ist ++i und i++ völlig gleich schnell für int, double und so. für selbstgebaute iteratoren ist ++i potentiell schneller und man sollte deshalb gleich immer ++i schreiben, damit man's so gewohnt ist.

    @offtopic @volkard
    wo wir wieder beim thema wären 😃



  • mir fällt sofort ein, daß die summe von for(int i=1;i<=1000000;++i)s+=1.0/i; sich gar nicht so genau anfühlt, wie for(int i=1000000;i>=1;--i)s+=1.0/i;
    aber in dem fall, wo er feststellen will, bis wohin er aufsummieren muß, fällt mir nix ganz einfaches ein, um die sache stabiler zu machen.
    hast du ne idee?

    Leider habe ich keine Idee. Habe mich aber auch schon gefragt, ob man etwas schöneres produzieren kann. Werde mir aber mal mit Stift und Papier Gedanken machen.


Anmelden zum Antworten