Leibniz-Reihe in C++

Neue Frage »

AstroNerd Auf diesen Beitrag antworten »
Leibniz-Reihe in C++
Hallo User des Matheboards,
Ich habe eben ein Programm in C++ geschrieben, welches die Leibnitz-Reihe zur Berechnung von Pi darstellt.

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
 
#include <iostream>
#include<math.h>
using namespace std;
int main()
{
	cout << "Wählen Sie eine sehr große Zahl aus.\n" ;
	int a;
	cin >> a;
	double P;
	double k;
	for(k = 0; k < a; k++)
	{ 
	P += pow(-1,k)/(2*k+1);
	}
	
	cout << "Pi ist ungefähr " << 4*P;
	
	cin.sync();
	cin.get();
	return 0;
}


Egal welche Zahl ich für a eingebe, es kommen gerade mal 5 Nachkommastellen raus (3.14159). Ich habe versucht, P auch als long double zu deklarieren, hat auch nicht funktioniert. Ich will ein Programm, bei dem mein Rechner (solange er kann und nicht abstürzt) einzelnd Pi Nachkommastellen berechnet/ausgibt.
Wie muss dieser Quelltext ausschauen/geändert werden, damit ich so viel Nachkommastellen rausbekomme, wie ich will ?
Mit freundlichem Gruß
AstroNerd
IfindU Auf diesen Beitrag antworten »
RE: Leibnitz-Reihe in C++
Siehe hier:
http://www.cplusplus.com/reference/iomanip/setprecision/

Es wird aber nicht beliebig genau werden können, weil irgendwann ein underflow auftritt.
AstroNerd Auf diesen Beitrag antworten »
RE: Leibnitz-Reihe in C++
Danke Freude
Was ist ein underflow ?
IfindU Auf diesen Beitrag antworten »
RE: Leibnitz-Reihe in C++
Gleitkommazahlen entscheiden sich immer, ob sie gerade eine große oder kleine Zahl darstellen. So können sie einen großen Bereich mit relativ kleinem Fehler abdecken. Das Problem ist, wenn du eine große Zahl hast, kann sie nicht viele Nachkommastellen darstellen. Wenn du eine kleine Zahl drauf addierst, kann die Gleitkommazahl die Information nicht verwerten und wirft sie weg. Effektiv addierst du irgendwann also nur noch Nullen auf. Von dem anderen Problem, dass die Divison irgendwann 0 liefert, weil das Ergebnis zu klein wird.

Edit: Eine Idee um das zu umgehen: Man addiert nicht immer zu der Zahl P, sondern summiert zwischenzeitlch viele kleine Zahlen zu einer anderen Zahl Q auf. Und die Zahl Q verrechnet man mit P.
Ich habe leider keine praktische Erfahrung wie viel man wirklich gewinnt.
HAL 9000 Auf diesen Beitrag antworten »

@AstroNerd

Du nutzt die Arkustangens-Potenzreihe



am Rande des Konvergenzintervalls, nämlich für - dort, wo sie extrem langsam konvergiert:

Der Approximationsfehler liegt etwa in der Größenordnung des letzten Gliedes vor Abbruch: Bei hast du demnach nur etwa 5 Nachkommastellen. unglücklich


Wenn du dieselbe Reihe (*) beispielsweise für



nutzt, geht es wesentlich flotter mit der Konvergenz.



P.S.: Noch ein paar Anmerkungen zum obigen C++-Quelltext:

1) p ist uninitialisiert - das geht gar nicht! Manche Compiler mögen das stillschweigend mit Null initialisieren, darauf verlassen kann man sich (insbesondere bei lokalen Variablen) aber nicht. Es sollte also dort besser "double p = 0.0;" in der Deklaration stehen.

2) Wieso "double k" ? Für den Laufindex der Schleife passt besser "int k".

3) Wenn du willst, dass mehr als 5 Nachkommastellen angezeigt (!) werden, dann musst du die Ausgabezeile z.B. in

cout << "Pi ist ungefähr " << setprecision(15) << 4*P;

ändern. Im Vorspann fehlt dazu noch ein

#include <iomanip>
Leopold Auf diesen Beitrag antworten »

Mit einem Korrektursummanden läßt sich die Konvergenz von



verbessern. Es gilt:



Als Beispiel nehmen wir :





Oder :



 
 
HAL 9000 Auf diesen Beitrag antworten »

Zitat:
Original von AstroNerd
Wie muss dieser Quelltext ausschauen/geändert werden, damit ich so viel Nachkommastellen rausbekomme, wie ich will ?

Mit double kommst du "nur" bis ca. 15 Nachkommastellen. Wenn du mehr wünschst, dann solltest du nochmal in deinen alten Thread schauen: Eulersche Zahl in C++
AstroNerd Auf diesen Beitrag antworten »

Vielen Dank smile Freude
HAL 9000 Auf diesen Beitrag antworten »

Wie im anderen Thread hier noch meine Vorstellung, wie ein C++-Programm zur -Berechnung basierend auf aussehen könnte, mit (in weiten Grenzen) beliebiger Stellenzahl unter Nutzung der GMP:

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
#include <iostream>
#include <iomanip>
#include <math.h>
#include <gmpxx.h>
using namespace std;

// berechnet atan(1/r); anwendbar fuer 1<r<46341
mpf_class mpf_atanr (int r)
{
    int rqneg = -r*r;
    mpf_class pot = 1;
    pot /= r;               // erstes Reihenglied
    mpf_class sum = pot;
    mpf_class sumtmp = 0;
    for (int k = 3; sumtmp != sum; k += 2)
    {
        sumtmp = sum;       // alte Summe "merken"
        pot /= rqneg;       // Potenz aktualisieren
        sum += pot / k;
        // Die Schleife endet, weil irgendwann pot kleiner ist
        // als das niederwertigste Bit von sum.
    }
    return sum;
}

int main (int argc, char *argv[])
{
    int Digits = 1000;
    if (argc > 1)
    {
        Digits = atoi(argv[1]);
    }
    mpf_set_default_prec((int)(Digits*log(10.0)/log(2.0)+16));
    mpf_class pi = 16*mpf_atanr(5)-4*mpf_atanr(239);
    cout << "pi = " << setprecision(Digits+1) << pi;
    return 0;
}
Rechenzeit für 100000 Stellen (auf i7 4GHz, nur ein Thread): ca. 5 Sekunden
Neue Frage »
Antworten »



Verwandte Themen

Die Beliebtesten »
Die Größten »
Die Neuesten »