sinus funktion mit taylorreihe entwickeln



  • hallo,

    wir sollen in unserem c-kurs die sinus formel in mithilfe der taylorreihe programmieren. die taylorreihe ist gegeben: sum(,n=0,\inf) (-1)^n (x^(2n+1))/(2n+1)! nebenbei: kann man das auch mit einem Summenzeichen darstellen sowie hier?

    was ich bis jetzt schon gemacht hab ist folgendes:

    #include <stdio.h>
    #include <math.h>
    
    int fak (int a) {
    
    	int x,i,fak;
    		fak=1;
    		x=a;
    
    	for (i=0; i<=x; i++){
    		fak=fak*i;
    	}
    	return fak;
    }
    
    main() {
    	float x, sinx, zaehler, nenner;
    	int n, i;
    
    		printf("Bitte geben Sie ein Argument x ein, von dem der Sinus berechnet werden soll und eine postive ganze Zahl n, weclhe den Genauigkeitsbereich bestimmt\n");
    		printf("x: ");
    		scanf("%f", &x);
    		printf("n: ");
    		scanf("%d", &n);
    		sinx=0;
    
    	for (i=0; i<=n; i++){
    
    		zaehler=pow(x,2*i+1);
    		nenner=fak(2*i+1);
    		sinx = sinx + (pow(-1, n)*(zaehler/nenner));
    
    	}
    		printf("sin(%f) = %f\n",x,sinx);
    		system("pause");
    }
    

    Er liefert nicht den richtigen Sinuswert. Er liefert immer 1.#INF00. Also viell irgendetwas mit dem Datentyp? Danke im Voraus!



  • Deine Fakultätsfunktion liefert immer 0, weil deine for-Schleife im ersten Durchlauf fak mit 0 multipliziert. Du solltest dich beizeiten mal mit den Möglichkeiten des Debuggings auseinandersetzen, dann würdest du sowas selbst finden.

    PS 1: Der Algorithmus ist nicht besonders optimal, weil z.B. die Fakultätswerte sehr schnell sehr groß werden und überlaufen können. Überlege dir, wie du die Reihe ohne Verwendung einer Fakultätsfunktion berechnen kannst.

    PS 2: Mit tex-Tags: sinx=n=0(1)nx2n+1(2n+1)!\sin x = \sum_{n=0}^\infty (-1)^n \frac{x^{2n+1}}{(2n+1)!}



  • Die Formel vllt nicht so naiv umstezen wie sie da steht.

    Die einzelnden Summanden kann man schreiben als
    xnn!=x1x2xn1xn\frac{x^n}{n!} = \frac{x}{1}\cdot\frac{x}{2}\cdot\cdots\cdot\frac{x}{n-1}\cdot\frac{x}{n}
    da fällt das Problem mit den großen Fakultäten weg.

    Wenn man die einzelnden Summanden zwischen speichert kommt von Summand zu Summand also nur eine TermFaktor der Form:
    xn\frac{x}{n}
    dazu. Das ist ein gutartiger TermFaktor.
    Hoffe das hilft.



  • danke für eure antworten. habe jetzt die fakultätsfkt so angepasst, dass die schleife darin mit i=1 beginnt. dennoch spuckt mir die main funktion immer totalen quatsch aus für sinx. entweder 1.#INF00 oder 1.#IND00 oder Zahlen, die aber total falsch sind. Leider bekommen für nur für diese Taylorreihe Punkte und der Dozent hat schon angedeutet, dass wir es nach Zähler, Nenner und dem alternierenden Vorzeichen unterteilen sollen. Deswegen würde ich es schon gern damit hinkriegen.



  • Das sollte pow(-1, i) sein.



  • oha. was für ein fehler! aber leider immer noch das selbe problem 😡



  • Eigentlich nicht. Was gibst du denn ein und was bekommst du raus?



  • ich gebe zb. ein x=10 und n = 10 und erhalte sinx= -928293191680
    oder x=3 und n=100 ergibt sinx = -1.#IND00 🙄



  • Die Reihe konvergiert für große x ziemlich langsam, da werden 10 Glieder nicht ausreichen. Probier mal x in "normalen" Argumentbereichen für den Sinus, irgendwas zwischen 0 und pi/2. Und für das zweite Beispiel: Hast du eine Idee, wie groß die Fakultät von 100 ist? Kannst es ja mal testweise bei Wolfram Alpha ausrechnen lassen. Spoiler: Der int-Wertebereich ist zu klein dafür.



  • In welchem Bereich ist der Sinus sinnvoll? -π bis +π.

    Kann dein int überhaupt 100! aufnehmen? Nein. Maximal 12! bei 32-Bit



  • Wenn du die Tipps von ScottZhang und Bashar (PS 1) beherzigst, kommst du auch mit 100 Durchläufen klar.



  • na klar logisch. habs da mit den fakultäten etwas zu weit getrieben. danke dirkb, bashar und scottzhang!! habs jetz auch soweit repariert und zusätzlich noch ne eingabe im gradmaß eingebaut, die dann ins bogenmaß umgerechnet wird. ab 270grad werden leider meine ergebnisse kleiner als -1 aber was solls. 80% der aufgabe sollten erfüllt sein. wobei es mich doch schon interessieren würde 😕

    #include <stdio.h>
    #include <math.h>
    #define PI 3.14159
    int fak (int a) {
    
    	int x,i,fak;
    		fak=1;
    		x=a;
    
    	for (i=1; i<=x; i++){
    		fak=fak*i;
    	}
    	return fak;
    }
    
    main() {
    	float bog, grad, sinx=0, zaehler, nenner;
    	int n, i;
    
    		printf("Bitte geben Sie ein Argument im Gradmass ein (0-360), von dem der Sinus berechnet werden soll und eine postive ganze Zahl n, weclhe den Genauigkeitsbereich bestimmt\n");
    
    		printf("\nArgument im Gradmass: ");
    		scanf("%f", &grad);
    		bog=(grad*PI)/180;
    		printf("Argument im Bogenmass: %.2f\n", bog);
    
    		printf("\nn: ");
    		scanf("%d", &n);
    
    	for (i=0; i<=n; i++){
    
    		zaehler=pow(bog,2*i+1);
    		nenner=fak(2*i+1);
    		sinx = sinx + (pow(-1, i)*(zaehler/nenner));
    
    	}
    		printf("sin(%.2f) = %.2f\n",bog,sinx);
    		system("pause");
    }
    


  • taka schrieb:

    habs jetz auch soweit repariert

    Sieht nicht so aus. Das ist doch exakt noch der gleiche Algorithmus. Ab n=13 hast du Überläufe, kannst also nicht gerade viele Reihenglieder aufsummieren, wodurch du für große x sehr große Ungenauigkeiten bekommst.

    ScottZhang hat dir schon den Tipp gegeben, wie man das löst.



  • naja. ich weiß dass sein weg sicher auch zum ziel führt und sicherlich auch der effektivere ist. aber ich möchte an dieser stelle stur sein (bestimmt auch, weil der dozent gesagt hat wir sollen/können das mit einer Fakultätsfunktion lösen). außerdem hat seine umformung sicherlich nichts mehr mit der taylorreihe zu tun denk ich. und selbst bei kleinem n (n=7) und kleinem x (x=270grad=3/2pi) kommt -7.05 raus. irgendwo habe ich doch noch einen denkfehler oder?



  • Du berechnest ja auch die Fakultät von 2*n+i. Bei n=7 wäre das 15!

    Du kannst jetzt noch unsigned long long für die Fakultät und double statt float nehmen.
    Das bringt dich dann bis 20!. ( also n=9)

    Das bleibt aber trotzdem ein Holzweg.

    Mit dem anderen Verfahren lommst du weiter.



  • taka99 schrieb:

    naja. ich weiß dass sein weg sicher auch zum ziel führt und sicherlich auch der effektivere ist. aber ich möchte an dieser stelle stur sein (bestimmt auch, weil der dozent gesagt hat wir sollen/können das mit einer Fakultätsfunktion lösen). außerdem hat seine umformung sicherlich nichts mehr mit der taylorreihe zu tun denk ich. und selbst bei kleinem n (n=7) und kleinem x (x=270grad=3/2pi) kommt -7.05 raus. irgendwo habe ich doch noch einen denkfehler oder?

    Natürlich ist das noch die Taylorreihe. Nur die Reihenfolge in der man Teilwerte miteinander hat sich verbessert. Bleib Stur so lange Du willst oder gib die bessere Lösung ab, liegt bei Dir 😉



  • taka99 schrieb:

    außerdem hat seine umformung sicherlich nichts mehr mit der taylorreihe zu tun denk ich.

    Doch, natürlich, das ist nur eine schlauere Version die Taylorreihe zu berechnen.

    und selbst bei kleinem n (n=7) und kleinem x (x=270grad=3/2pi) kommt -7.05 raus. irgendwo habe ich doch noch einen denkfehler oder?

    3/2pi ist nicht "klein". Versuch mal Werte zwischen -pi/2 und +pi/2. Und möglichst größeres n.



  • Wenn du dir die Formel mal ausschreibst...
    sinx=n=0(1)nx2n+1(2n+1)!=x1xxx123+xxxxx12345xxxxxxx1234567+\sin x = \sum_{n=0}^\infty (-1)^n \frac{x^{2n+1}}{(2n+1)!} = \frac{x}{1}-\frac{x\cdot x\cdot x}{1\cdot 2\cdot 3}+\frac{x\cdot x\cdot x\cdot x\cdot x}{1\cdot 2\cdot 3\cdot 4\cdot 5} -\frac{x\cdot x\cdot x\cdot x\cdot x\cdot x\cdot x}{1\cdot 2\cdot 3\cdot 4\cdot 5\cdot 6\cdot 7} + - \cdots

    ..., dann siehst du, dass sich bei jeden Summanden relativ wenig ändert: Der Faktor xx2n(2n+1)-\frac{x\cdot x}{2n\cdot (2n+1)}
    Das gibt nicht so riesige Werte wie bei der Fakultät.

    Du nimmst dir in der Schleife den Summanden aus dem vorhergehenden Durchgang und multiplizierst ihn mit der Änderung.

    Du sparst dir die Fakültät und auch die pow-Funktion.

    ~Danke an ScottZhang und Bashar für die Texvorlagen~


Anmelden zum Antworten