Frage

Wie kann ich den Wert von PI mit C# berechnen?

Ich dachte, es würde durch eine rekursive Funktion geschehen. Wenn ja, wie würde es aussehen und gibt es mathematische Gleichungen, die es untermauern?

Ich bin nicht allzu wählerisch, wenn es um die Leistung geht, sondern vor allem darum, wie man aus lerntechnischer Sicht vorgeht.

War es hilfreich?

Lösung

Wenn Sie eine Rekursion wünschen:

PI = 2 * (1 + 1/3 * (1 + 2/5 * (1 + 3/7 * (...))))

Dies würde nach einigem Umschreiben lauten:

PI = 2 * F(1);

mit F(i):

double F (int i) {
    return 1 + i / (2.0 * i + 1) * F(i + 1);
}

Isaac Newton (Sie haben vielleicht schon einmal von ihm gehört ;) ) hat sich diesen Trick ausgedacht.Beachten Sie, dass ich der Einfachheit halber die Endbedingung weggelassen habe.Im wirklichen Leben braucht man so etwas.

Andere Tipps

Wie wäre es mit:

double pi = Math.PI;

Wenn Sie eine höhere Genauigkeit wünschen, müssen Sie ein algorithmisches System und den Typ Decimal verwenden.

Wenn Sie sich diesen wirklich guten Ratgeber genau ansehen:

Muster für die parallele Programmierung:Verstehen und Anwenden paralleler Muster mit dem .NET Framework 4

Auf Seite 70 finden Sie diese nette Implementierung (mit geringfügigen Änderungen meinerseits):

static decimal ParallelPartitionerPi(int steps)
{
    decimal sum = 0.0;
    decimal step = 1.0 / (decimal)steps;
    object obj = new object();

    Parallel.ForEach(
        Partitioner.Create(0, steps),
        () => 0.0,
        (range, state, partial) =>
        {
            for (int i = range.Item1; i < range.Item2; i++)
            {
                decimal x = (i - 0.5) * step;
                partial += 4.0 / (1.0 + x * x);
            }

            return partial;
        },
        partial => { lock (obj) sum += partial; });

    return step * sum;
}

Es gibt ein paar wirklich, wirklich alte Tricks, die ich hier nicht sehe, wundert mich.

Atan (1) == PI/4, also eine alte Kastanie, wenn eine vertrauenswürdige Bogen-Tangent-Funktion vorhanden ist, 4*Atan (1).

Eine sehr niedliche Schätzung mit festem Verhältnis, die den alten Western 22/7 so aussieht, als wäre Schmutz 355/113, was zu mehreren Dezimalstellen (mindestens drei oder vier) gut ist.In manchen Fällen ist dies sogar gut genug für die Ganzzahlarithmetik:Mit 355 multiplizieren und dann durch 113 dividieren.

355/113 lässt sich auch leicht einprägen (zumindest für manche Leute):Zählen Sie eins, eins, drei, drei, fünf, fünf und denken Sie daran, dass Sie die Ziffern im Nenner und Zähler benennen (wenn Sie vergessen, welches Triplett oben steht, wird es normalerweise durch eine Mikrosekunde geklärt).

Beachten Sie, dass Sie rund um die Uhr Folgendes erhalten:3,14285714, was im Tausendstelbereich falsch ist.

355/113 ergibt 3,14159292, was bis zum Zehnmillionstel nicht falsch ist.

Acc.zu /usr/include/math.h auf meiner Box, M_PI ist #definiert als:3.14159265358979323846, was wahrscheinlich so weit ist, dass es so ist.

Die Lektion, die Sie durch die Schätzung von PI erhalten, ist, dass es viele Möglichkeiten gibt, es wird jemals perfekt sein, und Sie müssen sie durch beabsichtigte Verwendung aussortieren.

355/113 ist eine alte chinesische Schätzung, und ich glaube, dass sie viele Jahre vor dem 22.7. liegt.Es wurde mir von einem Physikprofessor beigebracht, als ich noch Student war.

Guter Überblick über verschiedene Algorithmen:

Ich bin mir nicht sicher, welche Komplexität im ersten Link für den Gauss-Legendre-Salamin-Algorithmus angegeben wird (ich würde sagen: O(N log^2(N) log(log(N)))).

Ich ermutige Sie jedoch, es auszuprobieren, die Konvergenz ist da Wirklich schnell.

Außerdem bin ich mir nicht ganz sicher, warum ich versuche, einen recht einfachen prozeduralen Algorithmus in einen rekursiven umzuwandeln.

Beachten Sie Folgendes: Wenn Sie an der Leistung interessiert sind, sollten Sie mit einer begrenzten Genauigkeit arbeiten (normalerweise ist ein „Double“, ein „Float“ usw. erforderlich).Ausgabe) macht nicht wirklich Sinn, da die offensichtliche Antwort in einem solchen Fall einfach darin besteht, den Wert fest zu codieren.

Hier ist ein Artikel zur Berechnung von PI in C#:

http://www.boyet.com/Articles/PiCalculator.html

Was ist PI?Der Umfang eines Kreises geteilt durch seinen Durchmesser.

In der Computergrafik können Sie einen Kreis zeichnen/zeichnen, dessen Mittelpunkt bei 0,0 liegt, ausgehend von einem Anfangspunkt x,y. Der nächste Punkt x',y' kann mit einer einfachen Formel ermittelt werden:x' = x + y / h :y' = y - x' / h

h ist normalerweise eine Potenz von 2, so dass die Division einfach durch eine Verschiebung (oder Subtraktion vom Exponenten bei einem Double) erfolgen kann.h möchte auch der Radius r Ihres Kreises sein.Ein einfacher Ausgangspunkt wäre x = r, y = 0 und dann c die Anzahl der Schritte zu zählen, bis x <= 0, um ein Viertel eines Kreises zu zeichnen.PI ist 4 * c/r oder PI ist 4 * c/h

Eine Rekursion bis in eine große Tiefe ist für ein kommerzielles Programm normalerweise unpraktisch, aber die Schwanzrekursion ermöglicht die rekursive Darstellung eines Algorithmus, während er als Schleife implementiert wird.Rekursive Suchalgorithmen können manchmal mithilfe einer Warteschlange anstelle des Stapels des Prozesses implementiert werden. Die Suche muss aus einer Sackgasse zurückverfolgen und einen anderen Pfad einschlagen. Diese Rückverfolgungspunkte können in eine Warteschlange gestellt werden, und mehrere Prozesse können die Punkte aus der Warteschlange entfernen und es versuchen andere Wege.

Berechnen Sie so:

x = 1 - 1/3 + 1/5 - 1/7 + 1/9  (... etc as far as possible.)
PI = x * 4

Du hast Pi!!!

Das ist die einfachste Methode, die ich kenne.

Der Wert von PI nähert sich langsam dem tatsächlichen Wert von Pi (3,141592165......) an.Je öfter Sie iterieren, desto besser.

Hier ist ein schöner Ansatz (von der wichtigste Wikipedia-Eintrag zu pi);Sie konvergiert viel schneller als die oben besprochene einfache Formel und eignet sich durchaus für eine rekursive Lösung, wenn Sie die Rekursion als Lernübung durchführen möchten.(Angenommen, Sie möchten etwas lernen, gebe ich keinen tatsächlichen Code an.)

Die zugrunde liegende Formel ist dieselbe wie oben, jedoch werden bei diesem Ansatz die Teilsummen gemittelt, um die Konvergenz zu beschleunigen.

Definieren Sie eine Zwei-Parameter-Funktion, pie(h, w), so dass:

pie(0,1) = 4/1
pie(0,2) = 4/1 - 4/3
pie(0,3) = 4/1 - 4/3 + 4/5
pie(0,4) = 4/1 - 4/3 + 4/5 - 4/7
... and so on

Ihre erste Gelegenheit, die Rekursion zu erkunden, besteht also darin, diese „horizontale“ Berechnung zu codieren, wenn der Parameter „width“ zunimmt (für „height“ von Null).

Fügen Sie dann die zweite Dimension mit dieser Formel hinzu:

pie(h, w) = (pie(h-1,w) + pie(h-1,w+1)) / 2

was natürlich nur für Werte von h größer als Null verwendet wird.

Das Schöne an diesem Algorithmus ist, dass Sie ihn ganz einfach mit einer Tabellenkalkulation nachbilden können, um Ihren Code zu überprüfen, während Sie die Ergebnisse untersuchen, die durch immer größere Parameter erzielt werden.Wenn Sie pie(10,10) berechnen, verfügen Sie über einen ungefähren Wert für pi, der für die meisten technischen Zwecke ausreicht.

Enumerable.Range(0, 100000000).Aggregate(0d, (tot, next) => tot += Math.Pow(-1d, next)/(2*next + 1)*4)
using System;

namespace Strings
{
    class Program
    {
        static void Main(string[] args)
        {

/*          decimal pie = 1; 
            decimal e = -1;
*/
            var stopwatch = new System.Diagnostics.Stopwatch();
            stopwatch.Start(); //added this nice stopwatch start routine 

  //leibniz formula in C# - code written completely by Todd Mandell 2014
/*
            for (decimal f = (e += 2); f < 1000001; f++)
            {
                 e += 2;
                 pie -= 1 / e;
                 e += 2;
                 pie += 1 / e;
                 Console.WriteLine(pie * 4);
            }

                 decimal finalDisplayString = (pie * 4);
                 Console.WriteLine("pie = {0}", finalDisplayString);
                 Console.WriteLine("Accuracy resulting from approximately {0} steps", e/4); 
*/

// Nilakantha formula - code written completely by Todd Mandell 2014
// π = 3 + 4/(2*3*4) - 4/(4*5*6) + 4/(6*7*8) - 4/(8*9*10) + 4/(10*11*12) - (4/(12*13*14) etc

            decimal pie = 0;
            decimal a = 2;
            decimal b = 3;
            decimal c = 4;
            decimal e = 1;

            for (decimal f = (e += 1); f < 100000; f++) 
            // Increase f where "f < 100000" to increase number of steps
            {

                pie += 4 / (a * b * c);

                a += 2;
                b += 2;
                c += 2;

                pie -= 4 / (a * b * c);

                a += 2;
                b += 2;
                c += 2;

                e += 1;
            }

            decimal finalDisplayString = (pie + 3);
            Console.WriteLine("pie = {0}", finalDisplayString);
            Console.WriteLine("Accuracy resulting from {0} steps", e); 

            stopwatch.Stop();
            TimeSpan ts = stopwatch.Elapsed;
            Console.WriteLine("Calc Time {0}", ts); 

            Console.ReadLine();

         }
     }
 }
    public static string PiNumberFinder(int digitNumber)
    {
        string piNumber = "3,";
        int dividedBy = 11080585;
        int divisor = 78256779;
        int result;

        for (int i = 0; i < digitNumber; i++)
        {
            if (dividedBy < divisor)
                dividedBy *= 10;

            result = dividedBy / divisor;

            string resultString = result.ToString();
            piNumber += resultString;

            dividedBy = dividedBy - divisor * result;
        }

        return piNumber;
    }

In jedem Produktionsszenario würde ich Sie dazu zwingen, den Wert bis zur gewünschten Anzahl von Dezimalstellen nachzuschlagen und ihn als „Konstante“ an einem Ort zu speichern, an dem Ihre Klassen darauf zugreifen können.

(es sei denn, Sie schreiben wissenschaftliche „Pi“-spezifische Software ...)

Hinsichtlich...

...wie man aus lerntechnischer Sicht dabei vorgeht.

Versuchen Sie zu lernen, wissenschaftliche Methoden zu programmieren?oder um Produktionssoftware zu produzieren?Ich hoffe, dass die Community dies als eine berechtigte Frage und nicht als Trottel ansieht.

In jedem Fall denke ich, dass das Schreiben eines eigenen Pi ein gelöstes Problem ist.Dmitry hat die Konstante „Math.PI“ bereits gezeigt.Greifen Sie ein anderes Problem im selben Raum an!Entscheiden Sie sich für generische Newton-Näherungen oder etwas Raffiniertes.

@Thomas Kammeyer:

Beachten Sie, dass Atan(1.0) ziemlich oft fest codiert ist, sodass 4*Atan(1.0) nicht wirklich ein „Algorithmus“ ist, wenn Sie eine Bibliotheks-Atan-Funktion aufrufen (einige haben bereits vorgeschlagen, tatsächlich fortzufahren, indem Sie Atan(x) durch ersetzen eine Reihe (oder ein unendliches Produkt) dafür und werte sie dann bei x=1 aus.

Auch, Es gibt nur sehr wenige Fälle, in denen Sie Pi mit einer Genauigkeit von mehr als ein paar zehn Bit benötigen würden (was leicht fest codiert werden kann!).Ich habe an Anwendungen in der Mathematik gearbeitet, bei denen ich zur Berechnung einiger (ziemlich komplizierter) mathematischer Objekte (die Polynome mit ganzzahligen Koeffizienten waren) Arithmetik mit reellen und komplexen Zahlen (einschließlich der Berechnung von Pi) mit einer Genauigkeit von bis zu a durchführen musste ein paar Millionen Bits...aber das kommt 'im wirklichen Leben' nicht sehr häufig vor :)

Sie können das folgende Beispiel nachschlagen Code.

Ich mag dieses Papier, die erklärt, wie π basierend auf einer Taylor-Reihenentwicklung für den Arcustangens berechnet wird.

Das Papier beginnt mit der einfachen Annahme, dass

Atan(1) = π/4 Bogenmaß

Atan(x) kann mit der Taylor-Reihe iterativ geschätzt werden

atan(x) = x - x^3/3 + x^5/5 - x^7/7 + x^9/9...

Der Artikel zeigt auf, warum dies nicht besonders effizient ist, und führt anschließend eine Reihe logischer Verfeinerungen der Technik durch.Sie stellen auch ein Beispielprogramm zur Verfügung, das π auf einige tausend Stellen berechnet, komplett mit Quellcode, einschließlich der erforderlichen mathematischen Routinen mit unendlicher Genauigkeit.

Der folgende Link zeigt, wie man die Pi-Konstante basierend auf ihrer Definition als Integral berechnet, das als Grenzwert einer Summation geschrieben werden kann. Das ist sehr interessant:https://sites.google.com/site/rcorcs/posts/calculatedthepiconstantDie Datei „Pi als Integral“ erklärt diese in diesem Beitrag verwendete Methode.

Beachten Sie zunächst, dass C# das Math.PI-Feld des .NET Frameworks verwenden kann:

https://msdn.microsoft.com/en-us/library/system.math.pi(v=vs.110).aspx

Das Schöne daran ist, dass es sich um ein Double mit voller Genauigkeit handelt, das Sie entweder verwenden oder mit berechneten Ergebnissen vergleichen können.Die Registerkarten unter dieser URL haben ähnliche Konstanten für C++, F# und Visual Basic.

Um mehr Orte zu berechnen, können Sie Ihren eigenen Code mit erweiterter Genauigkeit schreiben.Eines, das schnell zu programmieren und einigermaßen schnell und einfach zu programmieren ist:

Pi = 4 * [4 * Arctan (1/5) - Arctan (1/239)]

Diese Formel und viele andere, darunter auch einige, die erstaunlich schnell konvergieren, wie etwa 50 Ziffern pro Term, finden Sie bei Wolfram:

Wolfram Pi-Formeln

PI (π) kann mit berechnet werden unendliche Serie.Hier zwei Beispiele:

Gregory-Leibniz-Reihe:

π/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - ...

C#-Methode:

public static decimal GregoryLeibnizGetPI(int n)
{
    decimal sum = 0;
    decimal temp = 0;
    for (int i = 0; i < n; i++)
    {
        temp = 4m / (1 + 2 * i);
        sum += i % 2 == 0 ? temp : -temp;
    }
    return sum;
}

Nilakantha-Serie:

π = 3 + 4 / (2x3x4) - 4 / (4x5x6) + 4 / (6x7x8) - 4 / (8x9x10) + ...

C#-Methode:

public static decimal NilakanthaGetPI(int n)
{
    decimal sum = 0;
    decimal temp = 0;
    decimal a = 2, b = 3, c = 4;
    for (int i = 0; i < n; i++)
    {
        temp = 4 / (a * b * c);
        sum += i % 2 == 0 ? temp : -temp;
        a += 2; b += 2; c += 2;
    }
    return 3 + sum;
}

Der Eingabeparameter n für beide Funktionen stellt die Anzahl der Iterationen dar.

Die Nilakantha-Reihe konvergiert im Vergleich zur Gregory-Leibniz-Reihe schneller.Die Methoden können mit folgendem Code getestet werden:

static void Main(string[] args)
{
    const decimal pi = 3.1415926535897932384626433832m;
    Console.WriteLine($"PI = {pi}");

    //Nilakantha Series
    int iterationsN = 100;
    decimal nilakanthaPI = NilakanthaGetPI(iterationsN);
    decimal CalcErrorNilakantha = pi - nilakanthaPI;
    Console.WriteLine($"\nNilakantha Series -> PI = {nilakanthaPI}");
    Console.WriteLine($"Calculation error = {CalcErrorNilakantha}");
    int numDecNilakantha = pi.ToString().Zip(nilakanthaPI.ToString(), (x, y) => x == y).TakeWhile(x => x).Count() - 2;
    Console.WriteLine($"Number of correct decimals = {numDecNilakantha}");
    Console.WriteLine($"Number of iterations = {iterationsN}");

    //Gregory-Leibniz Series
    int iterationsGL = 1000000;
    decimal GregoryLeibnizPI = GregoryLeibnizGetPI(iterationsGL);
    decimal CalcErrorGregoryLeibniz = pi - GregoryLeibnizPI;
    Console.WriteLine($"\nGregory-Leibniz Series -> PI = {GregoryLeibnizPI}");
    Console.WriteLine($"Calculation error = {CalcErrorGregoryLeibniz}");
    int numDecGregoryLeibniz = pi.ToString().Zip(GregoryLeibnizPI.ToString(), (x, y) => x == y).TakeWhile(x => x).Count() - 2;
    Console.WriteLine($"Number of correct decimals = {numDecGregoryLeibniz}");
    Console.WriteLine($"Number of iterations = {iterationsGL}");

    Console.ReadKey();
}

Die folgende Ausgabe zeigt, dass die Nilakantha-Reihe sechs korrekte Dezimalstellen von PI mit einhundert Iterationen zurückgibt, während die Gregory-Leibniz-Reihe fünf korrekte Dezimalstellen von PI mit einer Million Iterationen zurückgibt:

enter image description here

Mein Code kann getestet werden >> Hier

Hier ist eine schöne Möglichkeit:Berechnen Sie eine Reihe von 1/x^2 für x von 1 bis zu dem, was Sie wollen – je größer die Zahl, desto besser das Kuchenergebnis.Multiplizieren Sie das Ergebnis mit 6 und zu sqrt().Hier ist der Code in c# (nur main):

static void Main(string[] args)
    {
        double counter = 0;
        for (double i = 1; i < 1000000; i++)
        {

            counter = counter + (1 / (Math.Pow(i, 2)));

        }
        counter = counter * 6;
        counter = Math.Sqrt(counter);
        Console.WriteLine(counter);
    }
public double PI = 22.0 / 7.0;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top