C# Pi auf mehr als 14 Nachkomma stellen berechnen ?

Hydrano

Lieutenant
Registriert
März 2008
Beiträge
945
Hallo Leute,

der Titel dieses Thread beschreibt mein Problem eigenlich schon ganz gut.
Ich habe eine While schliefe um Pi so oft auf 14 nachkommastellen zu berechnen wie in eine textBox eingegeben wird, doch leider muss man in die textbox schon "999999999" also 9x die 9 eingeben um die CPU mal gearde 6sek. lang rechnen zu lassen (cpu: i5 750)
Zudem ist mir bewusst, dass nur ein Kern genutzt werden kann, es soll auch garnicht mehr nutzen.

Aber damit man in die Textbox nicht so hohe zahlen eingeben braucht wäre es schon nicht schlecht wenn man angeben könnte auf wie viele stellen es berechnet werden soll.
Int32 reicht dabei, denke ich? schon aus.
Dafür gibt es sicherlich einen ganz anderen Weg wie meinen.
Meiner sieht momentan so aus.

QuellText Ausschnitt schrieb:
while (cnt < schleife) //Schleife um 14 Nachkomma Stellen von Pi so oft wie eingegeben zu berechnen.
{
pi = Math.PI;
cnt++;
}
schleife = Einzugebende Zahl
cnt = counter der Zählt wie oft Pi auf 14 stellen bisher berechnet wurde, sobald cnt den wert von schleife erreicht hat wird die benötigte Zei ausgegeben.
 
Soweit ich weiß akzeptiert C# auch Eingaben in der Form "9E10" oder so ähnlich. E10 steht dabei für *10^10.

Ich bin mir jetzt aber nicht sicher ob das dein Problem löst....
 
Du berechnest da nicht Pi, du lässt nur den konstanten Wert Math.PI in deine Variable schreiben.

Für die Berechnung musst du einen eigenen Algorithmus schreiben. Für Pi gibt es da einige Näherungsformeln, auf wiki sollten da einige Gute dabei sein
 
Hm davon habe ich bisher noch nichts gehört.
Mir ist halt nur die Math.PI funtion für die PI berechnung bekannt und die gibt nur 14 Nachkomma stellen aus, das ist das was mich daran stört, ich will pi nicht auf 1000^1000 stellen berechnen.
Es geht darum das nicht so hohe Zahlen in die Box eingetippt werden müssen um ein messbares ergebniss zu erzielen wenn man beispielsweise 10 eingibt das halt 10x pi mit 10^10 nachkomma stellen berechnet wird und somit ein messbares ergbnis bei herum kommt.

Ich hoffe einfach mal ihr versteh wie ich das meine :D

Edit:
Wie genau müsste ich die Formel dann einbinden?


Edit2:
Ich meine wie bekomme ich soetwas in mein Programm?
\frac{1}{\pi} = 12 \sum^\infty_{k=0} \frac{(-1)^k (6k)! (13591409 + 545140134k)}{(3k)!(k!)^3 640320^{3k + 3/2}}.\!
siehe auch http://en.wikipedia.org/wiki/Chudnovsky_algorithm
 
Zuletzt bearbeitet:
Pi lässt sich nun mal nicht einfach mit der Pi-Formel berechnen...
Es gibt verschiedene Möglichkeiten Pi zu bestimmen, aber wäre es ncht einfacher Pi als Konstante zu verwenden?

Hast du eigentlich schon mal was von Google gehört? Da findet sich sicher ne Anleitung, wie man Pi näherungsweise bestimmen kann...
Selbst ein Blick in Wikipedia würde dir echt helfen... http://de.wikipedia.org/wiki/Kreiszahl
 
Pi lässt sich auch über einen relativ einfachen rekursiven Algorithmus bestimmen. Ich schau mal kurz in meine Unterlagen...
 
Ja Ok macht mich fertig -_-

Hast aber schon recht ziemlich recht, ich habe die wikipedia seite nicht komplett gelesen, da ich dachte das da nur Formeln stehen und keine spezifischen code Beispile und Google kann man wohl auch so ziemlich vergessen oder?
Also ich habe bei Google zumindest keine wirklich konkreten beispiele gefunden.
 
Vista Visual schrieb:
Ich meine wie bekomme ich soetwas in mein Programm?
siehe auch http://en.wikipedia.org/wiki/Chudnovsky_algorithm
hast du die summenformel schon ma irgendwo gesehen oder angewendet? wenn sollte die umsetzung eig ganz einfach sein. das zeichen und die symbole bedeuten einfach, dass du ne schleife von k = 0 bis x (= unendlich) machst. wäre dann z.b. folgendes konstrukt:
Code:
int faculty( int n ) { return n == 0 ? 1 : n * Faculty( n-1 ); }
double calculatePi( int Digits )
{
  double r = 0;

  for( int k = 0; k < Digits; k++ )
    r += (faculty( Math.pow( -1, k ) * (6 * k) ) * (13591409 + 545140134 * k)) / // oberer bruchstrich
         (faculty( 3 * k ) + Math.pow( faculty( k ), 3 ) * Math.pow( 640320, (3 * k + 3 / 2) )); // unterer bruchstrich
  
  return 1 / r; // reziproke, da nur 1/r
}
darauf geb ich aber keine gewähr, da ich mit c# noch nich wirklich was gemacht hab. ich will damit nur den ablauf aufzeigen.
 
Auch sehr interessant ist es, Pi mit einer Monte-Carlo-Methode zu berechnen. Das geht auch auf mehreren Kernen parallel :)
 
Code:
    public static double createZeroDotXZeroOne(int zeros) {
        String a = "0.";
        for(int i = 0;i<zeros;i++) {
            a += 0;
        }
        a += 1;
        return Double.parseDouble(a);
    }

    public static double calcPi(int digits) {
        boolean calcing = true;
        double diff = createZeroDotXZeroOne(digits);
        double calcedPi = 0.0, oldCalcedPi = 0.0, swap = 4.0, sum = 0.0;
        int i = 0;
        while(calcing) {
            sum += (Math.pow(-1, i)/(2*i+1));
            swap = 4*sum;
            if(i>=1) {
                oldCalcedPi = calcedPi;
                calcedPi = swap;
                if(Math.abs(oldCalcedPi-calcedPi)<diff) {
                    calcing = false;
                }
            }
            i++;
        }
        return calcedPi;
    }
So hab ich es in Java geloest, geht aber sicher sauberer. Weiss grad auch nich auswendig welches Verfahren das ist.
 
Warum so schwer wenns einfach geht?

public class pi{

public static double foo(double n,int p)
{

if (n>=p)
return n*n;

return (2*n)-1+n*n/foo(n+1,p);
}



public static void main(String[] args)
{

int p = Integer.parseInt(args[0]);
System.out.println(4/(foo(1.0,p)));
}
}


Johann Heinrich Lambert publizierte 1770 einen Kettenbruch, der heute meist in der Form

7784cb70781f7ed59612e57fba4fb844.png


geschrieben wird. Pro Schritt ergeben sich etwa 0,76555 Dezimalstellen, was im Vergleich mit anderen Kettenbrüchen mit Bildungsgesetz hoch ist, sodass sich dieser Kettenbruch besonders gut zur Berechnung von π eignet.
 
Zuletzt bearbeitet:
Wenn du schon WiKi 1:1 kopierst, dann schreibe bitte das nächste Mal die Quelle dazu.
 
Velines schrieb:
Auch sehr interessant ist es, Pi mit einer Monte-Carlo-Methode zu berechnen. Das geht auch auf mehreren Kernen parallel :)

Das ist richtig! Dazu gibts mehr für den Threadverfasser auf: http://www.eveandersson.com/pi/monte-carlo-circle

Die Methodik die dahinter steckt ist rel. einfach. Monte Carlo ist so vielfältig dass man es sogar für die Annäherung an die Kreiszahl Pi verwenden kann, kommt aber ürsprünglich aus der Stochastik/Statistik ( Zufallsvariablen bestücken und Simulationen laufen lassen ).
 
Ich glaube du arbeitest da ein bisschen am Ziel vorbei

Vista Visual schrieb:
Code:
while (cnt < schleife) //Schleife um 14 Nachkomma Stellen von Pi so oft wie eingegeben zu berechnen.
{
pi = Math.PI;
cnt++;
}

PI wird hier nicht berechnet. Die Arbeit hat schon Microsoft erledigt und fix hinterlegt mit den 14 Stellen. Das ist dasselbe, wie wenn du schreibst pi = 3.1415xxxxxx

Sobald du die Compileroptimierungen einschaltest, wird er erkennen, dass die Zeile "pi=Math.PI;" eigentlich sinnlos ist und wegkürzen. Das einzige, was bleibt ist eine Variable, die sich bis zu einem gewissen Wert hochzählt und eventuell wird er das auch streichen, da sonst kein Code enthalten ist. Als Benchmark ist das also ziemlich ungeeignet.

Das erklärt dann auch, warum die ganze Berechnung pro Schleife dann auch nur 20 Takte braucht. Damit geht sich bei einer wirklichen Berechnung gerade einmal eine Integer Division aus.

Ein Algorithmus, der mehr als diese 14 Stellen berechnet wird mit Sicherheit nicht unter 1.000 Zeilen auskommen können und ist für einen Anfänger nicht zu realisieren. Recht einfache Algorithmen sind hier sehr schwierig zu implementieren, da ein Double nur eine begrenzte Genauigkeit von 52Bit hat, was ca. 14 Stellen entspricht. Um einen Algorithmus zu implementieren, muss man also zuerst einmal einen Double mit höherer Genauigkeit ausprogrammieren. Hier benötigt man zumindest Addition, Subtraktion, Multiplikation und Division, jeweils auch mit negativen Zahlen.

Sobald man wirklich viele Stellen berechnen will (z.B. 1 Mio.) wird es überhaupt ziemlich schnell sehr hochmathematisch, da man einen Algorithmus finden muss, mit dem man eine Multiplikation und Division durchführt, wo der Aufwand nicht quadratisch mit der Stellenlänge wächst. In den meisten Fällen (z.B. der Lambert Methode) wächst der Aufwand sogar zum Kubik. Bei der Division bzw. beim Quadrieren hat man schon mindestens einen quadratischen Aufwand und das Ganze dann noch einmal pro Stelle. Selbst für 10K Stellen würde ich da schon einmal ein paar Stunden bis Tage einrechnen.

Edit: Ein besseres Beispiel für einen selbst geschriebenen Benchmark ist das Berechnen von allen Primzahlen bis zu einer bestimmten Zahl. Das ist schon mit sehr einfachen Algorithmen möglich, auf die man auch von alleine kommen kann und man kann es nach und nach optimieren, um noch etwas schneller zu werden.
 
Zuletzt bearbeitet:
Richtig, so einfach ist das nicht machbar. Insbesondere wegen der Genauigkeit von Double-Werten.

.NET bietet leider von sich aus keine Bibliotheken für den Umgang mit überlangen Zahlen an. Es gibt aber welche im Internet als Open-Source zum Download. Allerdings sollte man beachten, dass bei hohen Stellenzahlen die Berechnung insbesondere von Multiplikation und Division sehr ineffizient wird (mind. O(n*log n) bei Multiplikation und O(n²) bei Division soweit ich weiss). Addition und Subtraktion immerhin in O(n).

Das dürfte auch der Hauptgrund sein, warum du im Wiki keinen Quellcode zur Berechnung finden wirst. Es geht mit einfacher Integer- und Float-Arithmethik nicht.
 
Zuletzt bearbeitet:
Zurück
Oben