E Fkt berechnen mit Anzahl der Summanden



  • Hallo,
    ich lerne gerade ein bisschen C und hab folgendes Programm als Aufgabe gehabt:

    ich geb mein x wert ein,
    meine Anzahl an summanden(von taylorreihe) und er soll mir e^x ausgeben.

    Code:

    int main(void)
    {
    	double x, g;  // Exponent, Genauigkeit
    	int n;        // Nenner, ist gleich i!
    	double z;     // Zähler ist gleich x^i
    	double si;    // die einzelnen Summanden
    	double s;     // Summe, ist gleich Resultat
    	int i;        // Nummer des aktuellen Summanden
    	printf("Berechnung von e^x \n\n");
    	printf("x = " ); scanf("%lf",&x);
    	printf("Genauigkeit g= "); scanf("%lf", &g);
    	printf(" i    Summand       Summe \n");
    	printf("--------------------------\n");
    
    	s=1.0; i =0; n=1; z=1.0;
    	do {
    		i++;
    		n = n*i;
    		z=z*x;
    		si = z/n; 
    		s = s + si;
    		printf("%3d %12.6f %12.6f\n", i, si, s);
    	} while ( i <= g);
    	return 0;
    }
    

    aber das haut nicht so ganz hin, ich hab keine Ahnung wieso.
    ich könnte mir vorstellen dass die zahlen einfach zu riesig werden weil ab dem 13. summanden macht er gigantische rechenfehler und zuvor passts so ziemlich.
    liegt es daran oder findet sonst noch jemand einen fehler?



  • Das Problem dürfte sein, dass die Werte einmal ziemlich groß werden (n! und x^n) und dann auch sehr klein (x^n/n!). Du könntest einfacherweise zB long double benutzen. Aber meinst du nicht, dass eine Näherung auf den 13. Grad reicht? 🙂



  • eigentlich nicht, weil bei der 10. näherungen z.B für e^5 mit dem programm rauskommt:

    147...

    richtig:
    148.41

    also noch sehr starke abweichung



  • Hallo,

    andii schrieb:

    ... weil ab dem 13. summanden macht er gigantische rechenfehler und zuvor passts so ziemlich.
    liegt es daran oder findet sonst noch jemand einen fehler?

    Das liegt daran, das dein n! bei n=13 INT_MAX überschreitet.
    Auch für einen UINT_MAX ist 13! zu viel.
    Intern wird ohne Warnung mit der Modulo-Arithmetik weiter gerechnet.

    Wenn du für n double nimmst, bekommst du auch nen vernünftigen Wert bei n = 13.
    Bei double kannst du bis ca. n = 170 gehen.

    #include <stdio.h>
    int main()
    {
        double sum = 1.0, i=1.0, j=1.0, z=1.0;
        int x = 5, g = 13, n;
    
        for ( n=1; n<g; n++, j++ ) 
            sum += (z*=x)/(i*=j);
        printf( "%lf\n", sum ); // OK
    	return 0;
    }
    

    Besser, 'kritische' Werte prüfen:

    #include <float.h>	// DBL_MAX, DBL_MIN
    #include <limits.h> // INT_MAX, UINT_MAX
    
    double Facu( unsigned n )
    {
    	unsigned j;
    	double i;
    
    	for ( j=1, i=1; j<=n; j++ )
    	{
    		i *= j;
    		if (i > DBL_MAX )   
    		{
    			fprintf( stderr, "Hasta la vista at: %d\n", j );
    			exit(1); // 1.#INF00
    		}
    	}
    	return i;
    }
    // main die zweite(recommended):  :p 
    int main()
    {
    	double sum = 1.0, z=1.0, add = 0.0;
    	unsigned int x = 5, g = 13, n; 
    
    	for ( n=1; n<g; n++  )
    	{
    		add = (z*=x)/Facu(n);
    		if ( add == 0 )// z.b. für sehr kleine (z*=x)
    		{
    			fprintf( stderr, "add == 0\n" );
    			break;
    		}
    		sum += add;
    	}
    	printf( "%lf\n", sum );	
    
    	// Vielleicht auch noch ganz interessant zum Angucken:
    	printf( "UINT_MAX: %u INT_MAX: %d\n", UINT_MAX, INT_MAX );
    	printf( "Facu 12: %G\n", Facu( 12 ));
    	printf( "Facu 13: %G\n", Facu( 13 ));
    
    	printf( "%G\n", Facu( 170 ) );
    	printf( "%G\n", Facu( 171 ) );
    	printf( "%G\n", 0.0000000000000001/Facu( 170 ) ); // WoW !  :open_mouth: gerade noch so !
    	printf( "%G\n", 0.00000000000000001/Facu( 170 ) ); // Hier nicht mehr :D
    	return 0;
    }
    


  • danke für die tolle antwort, aber das ist mir viel zu fortgeschritten 😞

    habs mal versucht zu compilen, krieg ich das hier:

    1>d:\fh\info\mathe\mathe\mathe.cpp(36) : error C3861: 'exit': identifier not found

    sum += (z*=x)/(i*=j);
    

    und wie funktioniert diese zeile?
    hab ein wenig damit rumgespielt, und paar zeichen rausgenommen und so, kann mir das einer erklären?



  • Das ist gar nicht so schwer.
    int wird bei Überschreitung von INT_MAX negativ, unsigned int rechnet bei Überschreitung von UINT_MAX mit der Modulo-Arithmetik weiter, fängt also quasi wieder von vorn an zu zählen:

    #include <stdio.h>
    #include <limits.h> // INT_MAX, UINT_MAX
    
    int main()
    {
    	int in = INT_MAX;
    	unsigned int un = UINT_MAX;
    
    	printf("in: %d\n", in );
    	printf("un: %u\n", un );
    
    	// signed int wird bei überschreitung von INT_MAX negativ
    	in = in +1; 
    
    	// unsigned int rechnet mit der Modulo-Arithmetik weiter.
    	un = un +2; 
    
    	printf("in: %d\n", in );
    	printf("un: %u\n", un );
    
    	// Modulo-Arithmetik, un ist das gleiche wie (UINT_MAX + 2) % UINT_MAX
    	printf("Modulo-Arithmetik: %u\n", (UINT_MAX + 2) % UINT_MAX );
    
    	return 0;
    }
    


  • andii schrieb:

    d:\fh\info\mathe\mathe\mathe.cpp(36) : error C3861: 'exit': identifier not found

    Für exit:
    #include <stdlib.h>

    Das andere ist auch nur eine Kurzschreibform:
    z*=x -> z = zx
    i
    =j -> i = i*j



  • okay, more questions incoming, ich kuck mir das eben noch ein bisschen an 🙂



  • Wenn UINT einfach bei 0 weiterzählt sobald maximum erreicht ist, wieso krieg ich dann für +2 nur +1?

    for ( n=1; n<g; n++, j++ )
    sum += (z*=x)/(i*=j);

    das bedeutet also quasi:

    n=n+1

    sum(zähler) = z=z*x

    sum(nenner) = i=i*(j=j+1)

    was heißt das += ? sum = sum + ...?

    achso, und diese schnell schreibweisen, in welcher h datei stecken die? ich muss das (irgendwann mal) zu papier bringen (ohne compile check) und wenn ich das nicht weiss ist eher schlecht 😉

    Warum funktionierts hiermit nicht:

    for ( n=1; n<g; n++)
    sum = sum + ((z=z*x)/(i=i*(j=j+1)));

    noch ein zusatz:
    ich checke das hier nicht:

    double x;
    	x = 123456.1234;
    	printf("x=%8.3f",x);
    

    und anzeigen tut er mir x= 123456.1234
    wieso schneidet er nicht ab? x=123456.1 ?
    dann hätte ich meine field width eingehalten, und die dezimal vorgabe gebrochen? wie macht der pc das hier genau? wo setzt er prioritäten?
    wenn ich %7f mache, gibt er mir noch mehr an...?!



  • proggingmania schrieb:

    Besser, 'kritische' Werte prüfen:

    double i;
    // ...
    		if (i > DBL_MAX )   
    		{
    // ...
    		}
    	}
    }
    

    *g* das wuerd ich mir nochmal ueberlegen 😃



  • Hallo zusammen,

    ich glaube, das Problem sind hier zwar die großen Zahlen xnx^n und n!n!.
    Aber es gibt einen Ansatz, der diese Zahlen nicht benötigt.

    Sei ziz_i definiert als: zi=xii!z_i=\frac{x^i}{i!}
    D.h. wir betrachten uns hier mal den Schritt vom i-ten Summanden
    zum (i+1)-ten.
    Es gilt ja folgendes: xi+1=xixx^{i+1} = x^i \cdot x
    und analog für die Fakulät: (i+1)!=i!(i+1)(i+1)! = i! \cdot (i+1)

    Also gilt für zi+1z_{i+1} das Folgende:

    [latex]z_{i+1} = \frac{x^{i+1}}{(i+1)!}[/latex]
    
           [latex]z_{i+1} = \frac{x^i \cdot x}{i! \cdot (i+1)}[/latex]
    
           [latex]z_{i+1} = \frac{x^i}{i!} \cdot \frac{x}{i+1}[/latex]
    
           [latex]z_{i+1} = z_i \cdot \frac{x}{i+1}[/latex]
    

    Die Taylorentwicklung bis zum n-ten Glied von exp ist nun:

    [latex]exp(x) = \sum_{i=0}^{n} z_i[/latex]
    

    So, das war es von Seiten der Mathematik. Nun brauchst du nur noch
    die Schritte zu implementieren. Das sollte nun nicht mehr so schwer sein.

    Gruß mcr

    PS: ich habe diesen Thread nicht im Detail gelesen. Also bitte nicht auf den
    Schlips getreten fühlen, sollte einer meiner Vorposter diesen Ansatz schon
    einmal gepostet haben. 😉



  • andii schrieb:

    Wenn UINT einfach bei 0 weiterzählt sobald maximum erreicht ist,
    wieso krieg ich dann für +2 nur +1?

    Bei UINT_MAX + 1 fängt er wieder von vorn an zu zählen, ist also gleich 0.
    UINT_MAX + 2 == 1
    UINT_MAX + 3 == 2
    usw.

    andii schrieb:

    Warum funktionierts hiermit nicht:
    for ( n=1; n<g; n++)
    sum = sum + ((z=z*x)/(i=i*(j=j+1)));

    Doch, das geht, wenn du vorher j=0.0 initialisierst. Sonst bist
    du mit deiner Fakultät immer einen Schritt weiter und bekommst ein
    zu kleines Ergebnis.

    andii schrieb:

    achso, und diese schnell schreibweisen, in welcher h datei stecken die?

    In keiner. Das ist im Compiler 'eingebaut', also ein Standard-Sprachmittel von C.

    andii schrieb:

    double x;
        x = 123456.1234;
        printf("x=%8.3f",x);
    

    und anzeigen tut er mir x= 123456.1234
    wieso schneidet er nicht ab? x=123456.1 ?

    Anzeigen sollte er 123456.123. Abgeschnitten wird auch nichts, die
    Stellen werden nur 'versteckt'.
    Ein printf("x=%8.1f", x); sollte dir 123456.1 anzeigen.

    Blue-Tiger schrieb:

    proggingmania schrieb:

    Besser, 'kritische' Werte prüfen:

    double i;
    // ...
    		if (i > DBL_MAX )   
    		{
    // ...
    		}
    	}
    }
    

    *g* das wuerd ich mir nochmal ueberlegen 😃

    Die Abfrage erfüllt in diesem Fall ihren Zweck.
    Klappt leider nur, bei sehr großen Zahlen, wenn die Zahl i in den "1.#INF Modus" schaltet.

    Bei Abfragen wie z.B.

    i = DBL_MAX+1;
    würde in der Abfrage
    if (i > DBL_MAX )   
    {
    //.. hier passiert nix
    }
    

    nichts passieren, weil (i = DBL_MAX + 1) == DBL_MAX
    ist.
    😞

    Das hier bringt auch nix:
      num = DBL_MAX+1;
    
      printf("errno: %d\n", errno );		// 0 -> "OK"
      printf("finite: %d\n", _finite(num) );	// 1 -> "OK"
      printf("_isnan: %d\n", _isnan(num) );		// 0 -> "OK"
    

    Ein double merkt erst ziemlich spät, das ihm die Luft ausgeht:

    int main()
    {
      double num, add = 1E1;
    
      while(1)
      {
    	  num = 0.0;
    	  num = DBL_MAX + add;
    	  add *= 10;
    
    	  if( num > DBL_MAX )
    	  {
    	  	printf( "%G %G\n", num, add ); // Ausgabe: 1.#INF 1E+293
    	  	break;
    	  }
      }
       return 0;
    }
     // Ausgabe: 1.#INF 1E+293
    

    Hilft wohl nur ein Compiler, der long double unterstützt, dann müsste
    sowas hier eigentlich gehen:
    if ( (long double)i > DBL_MAX )
    🙂

    mcr schrieb:

    ....
    Aber es gibt einen Ansatz, der diese Zahlen nicht benötigt.
    ...

    😕



  • mcr schrieb:

    zi=xii!z_i=\frac{x^i}{i!}

    [latex]exp(x) = \sum_{i=0}^{n} z_i[/latex]
    

    das hilft mir ja nicht viel?



  • andii schrieb:

    das hilft mir ja nicht viel?

    Nicht wirklich. Denn schlussletztendlichstallerletztestens mußt du ja die Fakultät berechnen, nicht wahr doch.
    Und ?
    Läuft jetzt dein Proggie ?



  • ja es läuft danke 👍

    bin grad am nächsten problem, sinus als taylorreihe.
    da habe ich dann summanden die nur alle ungeraden exponenenten haben, als ^3 ^5 usw... und auch + und - abwechselnd zwischen den summanden, was mir gerade die größten probleme bereitet aber ich tüfftel noch ein wenig bevor ich wieder schreie 🙂



  • andii schrieb:

    mcr schrieb:

    zi=xii!z_i=\frac{x^i}{i!}

    [latex]exp(x) = \sum_{i=0}^{n} z_i[/latex]
    

    das hilft mir ja nicht viel?

    Es tut mir Leid, dass du meinen Beitrag nicht komplett verstanden hast.
    Du brauchst hierbei NICHT die Fakultät bestimmen!

    Der Knackpunkt liegt in dieser Zeile: zi+1=zixi+1z_{i+1} = z_i \cdot \frac{x}{i+1}

    Ok, für die, die es immer noch nicht verstehen, mal ein wenig Pseudocode:

    double summe = 0.;
        double summand = 1.;
    
        summe = summand;
        for i=0 to n do
           summand = summand * x / (i+1);
           summe   = summe + summand;
        end
    
        return summe;
    

    Nun bleib lediglich als Aufgabe übrig, diesen Pseudocode in C zu übersetzen.
    Und wie ihr seht: hier wird weder die Potenz noch die Fakultät bestimmt

    Gruß mcr

    Ach übrigens, so ähnlich geht das dann auch mit dem sinus! 😉



  • proggingmania schrieb:

    Denn schlussletztendlichstallerletztestens mußt du ja die Fakultät berechnen, nicht wahr doch.

    Wie zuvor geschrieben: deine Aussage ist falsch!

    Gruß mcr



  • Ach Quatsch.
    (i+1)! = i! * (i+1)
    Toll und nu ? Ist i! etwa keine Fakultät ? Bekomme ich i! etwa durch, ich zitiere mal frei, "Vermeidung von großen Zahlen" ?
    Ein x^1 kann ich auch nicht durch i! teilen, bevor ich i! habe.
    So, und wenn ich bei i! nen 1.#INF00 wegen Werteüberschreitung kriege, kann ich mir auch die Berechnung von (i+1)! in die Haare schmieren.
    Auch wenn i! ( sprich: i FAKULTÄT )vorher aus der Hutschachtel gezaubert kam. 😉

    🙂



  • proggingmania schrieb:

    Ach Quatsch.
    (i+1)! = i! * (i+1)
    Toll und nu ? Ist i! etwa keine Fakultät ? Bekomme ich i! etwa durch, ich zitiere mal frei, "Vermeidung von großen Zahlen" ?
    Ein x^1 kann ich auch nicht duchr i! teilen, bevor ich i! habe.
    So, und wenn ich bei i! nen 1.#INF00 wegen Werteüberschreitung kriege, kann ich mir auch die Berechnung von (i+1)! in die Haare schmieren.
    Auch wenn i! ( sprich: i FAKULTÄT )vorher aus der Hutschachtel genaubert kam. 😉

    🙂

    Hallo proggingmania,

    ich habe da mal ein paar Fragen zu deiner Person:
    -- Wie alt bist du?
    -- Inwiefern hast du mit Programmieren und Mathematik zu tun?

    Ich kann dich leider nicht verstehen. Wenn du dir die Aufgabe ansiehst,
    fällt dir auf, dass i! nicht benötigt wird. Schau dir mal meine Beiträge
    an: Hier habe ich eine Möglichkeit aufgezeigt, wie man ohne die Berechnung
    von i! auskommt. Ich habe sogar Pseudocode gepostet.

    Ich habe die exp(x) und sin(x) Berechnung implementiert und kam ohne
    Probleme mit double aus.

    Bitte tu mir einen Gefallen und überleg dir, was du mir hier antwortest,
    ich möchte nicht, dass das hier exskaliert.

    Aber ich muss dir Recht geben: i! und xix^i alleine zu berechnen
    sprengt dir die normalen Datentypen. Aber hier wird der Quotient aus beiden
    benötigt, dadurch bleiben die Zahlen im gebräuchlichen Wertebereich, wenn die
    Reihenfolge clever gewählt ist.

    Gruß mcr



  • mcr schrieb:

    Ich kann dich leider nicht verstehen. Wenn du dir die Aufgabe ansiehst,
    fällt dir auf, dass i! nicht benötigt wird. Schau dir mal meine Beiträge
    an: Hier habe ich eine Möglichkeit aufgezeigt, wie man ohne die Berechnung
    von i! auskommt. Ich habe sogar Pseudocode gepostet.

    Hallo mcr,
    Ich hatte die Definition von zi im Auge,

    mcr schrieb:

    Sei ziz_i definiert als: zi=xii!z_i=\frac{x^i}{i!}
    D.h. wir betrachten uns hier mal den Schritt vom i-ten Summanden
    zum (i+1)-ten.

    die auf der Berechnung von i! basiert.
    Deinem Pseudocode habe ich leider zu wenig Beachtung geschenkt. Das habe ich heute nachgeholt, in der Tat läßt sich damit die direkte Berechnung der großen Zahlen vermeiden. 👍
    Sorry for any inconvenience.
    Gruß,
    p.



  • okay also ich schaffe es nicht alleine, ich komme nicht drauf wie das geht.

    also der Sinus als Taylor:

    x - (x^3 / 3!) + (x^5 / 5! ) - (x^7/7!) ...

    wie man sieht wechseln die vorzeichen, da habe ich mir gedacht ich teile es auf in einen wert, wo alles abgezogen wird, und in einem wo alles addiert wird, und am ende verrechnen.

    und mit dem 3! 5! 7!... komme ich überhaupt nicht klar, ich habs so probiert mit den ungeraden zahlen:

    for(i=1;i<20;i=i+1) 
    		if (i/2 =! 0) {
    

    aber das problem ist jetzt, das es dann mit den fakultäten ja nicht stimmt wenn ich sage n=n*i, dann hätte ich ja 1*1, 1*3, 1*3*5 usw.. 😞

    HILFE 😃


Anmelden zum Antworten