Question

Comment puis-je calculer la valeur de PI en utilisant C# ?

Je pensais que ce serait via une fonction récursive, si oui, à quoi cela ressemblerait-il et y a-t-il des équations mathématiques pour le sauvegarder ?

Je ne suis pas trop pointilleux sur la performance, principalement sur la façon de s'y prendre d'un point de vue apprentissage.

Était-ce utile?

La solution

Si vous voulez de la récursion :

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

Cela deviendrait, après quelques réécritures :

PI = 2 * F(1);

avec F(je):

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

Isaac Newton (vous avez peut-être déjà entendu parler de lui ;) ) a inventé cette astuce.Notez que j'ai omis la condition finale, pour rester simple.Dans la vraie vie, vous en avez en quelque sorte besoin.

Autres conseils

Que diriez-vous d'utiliser :

double pi = Math.PI;

Si vous souhaitez une meilleure précision que cela, vous devrez utiliser un système algorithmique et le type Decimal.

Si vous regardez attentivement ce très bon guide :

Modèles pour la programmation parallèle :Comprendre et appliquer des modèles parallèles avec le .NET Framework 4

Vous trouverez à la page 70 cette jolie implémentation (avec des changements mineurs de ma part) :

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;
}

Il y a quelques astuces vraiment très anciennes que je suis surpris de ne pas voir ici.

atan (1) == pi / 4, donc un vieux châtaignier lorsqu'une fonction arc-tangente fiable est présente est 4 * Atan (1).

Une estimation très mignonne et fixe qui fait que l'ancien Western 22/7 ressemble à la saleté est de 355/113, ce qui est bon pour plusieurs décimales (au moins trois ou quatre, je pense).Dans certains cas, cela est même suffisant pour l’arithmétique des nombres entiers :multipliez par 355 puis divisez par 113.

355/113 est également facile à mémoriser (pour certaines personnes en tout cas) :comptez un, un, trois, trois, cinq, cinq et rappelez-vous que vous nommez les chiffres du dénominateur et du numérateur (si vous oubliez quel triplet va en haut, une pensée d'une microseconde va généralement le redresser).

Notez que 22/7 vous offre :3,14285714, ce qui est faux au millième.

355/113 vous donne 3,14159292, ce qui n'est pas faux jusqu'au dix millionième.

Acc.dans /usr/include/math.h sur ma boîte, M_PI est #défini comme :3.14159265358979323846 Ce qui est probablement bon dans la mesure où il va.

La leçon que vous obtenez en estimant PI est qu'il existe de nombreuses façons de le faire, aucune ne sera jamais parfaite, et vous devez les régler par utilisation prévue.

355/113 est une ancienne estimation chinoise, et je crois qu'elle est antérieure de plusieurs années au 22/7.Cela m'a été enseigné par un professeur de physique lorsque j'étais étudiant.

Bon aperçu des différents algorithmes :

Je ne suis pas sûr de la complexité revendiquée pour l'algorithme de Gauss-Legendre-Salamin dans le premier lien (je dirais O(N log^2(N) log(log(N)))).

Je vous encourage à l'essayer, cependant, la convergence est vraiment rapide.

De plus, je ne sais pas vraiment pourquoi essayer de convertir un algorithme procédural assez simple en un algorithme récursif ?

Notez que si vous êtes intéressé par les performances, travaillez avec une précision limitée (nécessitant généralement un « double », un « flotteur »,...sortie) n’a pas vraiment de sens, car la réponse évidente dans un tel cas est simplement de coder en dur la valeur.

Voici un article sur le calcul de PI en C# :

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

Qu’est-ce que l’IP ?La circonférence d'un cercle divisée par son diamètre.

En infographie, vous pouvez tracer/dessiner un cercle avec son centre à 0,0 à partir d'un point initial x,y, le point suivant x',y' peut être trouvé à l'aide d'une formule simple :x' = x + y / h :y' = y - x' / h

h est généralement une puissance de 2 afin que la division puisse être effectuée facilement avec un décalage (ou une soustraction de l'exposant sur un double).h veut aussi être le rayon r de votre cercle.Un point de départ simple serait x = r, y = 0, puis compter c le nombre d'étapes jusqu'à ce que x <= 0 pour tracer un quart de cercle.PI est 4 * c / r ou PI est 4 * c / h

La récursion à grande profondeur est généralement peu pratique pour un programme commercial, mais la récursion de queue permet à un algorithme d'être exprimé de manière récursive, tout en étant implémenté sous forme de boucle.Les algorithmes de recherche récursifs peuvent parfois être implémentés en utilisant une file d'attente plutôt que la pile du processus, la recherche doit revenir en arrière depuis une impasse et emprunter un autre chemin - ces points de retour en arrière peuvent être mis dans une file d'attente, et plusieurs processus peuvent retirer les points de la file d'attente et essayer d'autres chemins.

Calculez comme ceci :

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

Vous avez Pi !!!

C'est la méthode la plus simple que je connaisse.

La valeur de PI converge lentement vers la valeur réelle de Pi (3,141592165......).Si vous répétez plus de fois, mieux c'est.

Voici une belle approche (de l'entrée principale de Wikipédia sur pi);elle converge beaucoup plus rapidement que la formule simple évoquée ci-dessus et se prête tout à fait à une solution récursive si votre intention est de poursuivre la récursion comme exercice d'apprentissage.(En supposant que vous recherchez l'expérience d'apprentissage, je ne donne aucun code réel.)

La formule sous-jacente est la même que ci-dessus, mais cette approche fait la moyenne des sommes partielles pour accélérer la convergence.

Définissez une fonction à deux paramètres, pie(h, w), telle que :

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

Ainsi, votre première opportunité d'explorer la récursivité est de coder ce calcul "horizontal" à mesure que le paramètre "largeur" ​​augmente (pour une "hauteur" de zéro).

Ajoutez ensuite la deuxième dimension avec cette formule :

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

qui n’est bien entendu utilisé que pour les valeurs de h supérieures à zéro.

L'avantage de cet algorithme est que vous pouvez facilement le simuler avec une feuille de calcul pour vérifier votre code à mesure que vous explorez les résultats produits par des paramètres de plus en plus grands.Au moment où vous calculez pie(10,10), vous aurez une valeur approximative pour pi qui est suffisamment bonne pour la plupart des fins d'ingénierie.

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;
    }

Dans n'importe quel scénario de production, je vous obligerais à rechercher la valeur, jusqu'au nombre de décimales souhaité, et à la stocker sous forme de « const » quelque part où vos classes peuvent y accéder.

(sauf si vous écrivez un logiciel scientifique spécifique à 'Pi'...)

Concernant...

...comment s'y prendre du point de vue de l'apprentissage.

Essayez-vous d’apprendre à programmer des méthodes scientifiques ?ou pour produire des logiciels de production ?J'espère que la communauté considère cela comme une question valable et non comme une pinaille.

Dans les deux cas, je pense qu’écrire votre propre Pi est un problème résolu.Dmitry a déjà montré la constante « Math.PI ».Attaquez un autre problème dans le même espace !Optez pour des approximations génériques de Newton ou quelque chose de simple.

@Thomas Kammeyer :

Notez qu'Atan(1.0) est assez souvent codé en dur, donc 4*Atan(1.0) n'est pas vraiment un "algorithme" si vous appelez une fonction Atan de bibliothèque (un bon nombre déjà suggéré procèdent en effet en remplaçant Atan(x) par une série (ou un produit infini) pour celui-ci, puis l'évaluant à x=1.

Aussi, il y a très peu de cas où vous auriez besoin de pi avec plus de précision que quelques dizaines de bits (qui peut être facilement codé en dur !).J'ai travaillé sur des applications en mathématiques où, pour calculer certains objets mathématiques (assez compliqués) (qui étaient des polynômes à coefficients entiers), je devais faire de l'arithmétique sur des nombres réels et complexes (y compris le calcul de pi) avec une précision allant jusqu'à un quelques millions de bits...mais ce n'est pas très fréquent 'dans la vraie vie' :)

Vous pouvez rechercher l'exemple suivant code.

J'aime ce papier, qui explique comment calculer π sur la base d'un développement en série de Taylor pour Arctangent.

L'article part de l'hypothèse simple que

Atan(1) = π/4 radians

Atan(x) peut être estimé de manière itérative avec la série de Taylor

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

L'article souligne pourquoi cela n'est pas particulièrement efficace et continue en apportant un certain nombre d'améliorations logiques à la technique.Ils fournissent également un exemple de programme qui calcule π à quelques milliers de chiffres, complet avec le code source, y compris les routines mathématiques de précision infinie requises.

Le lien suivant montre comment calculer la constante pi en fonction de sa définition comme intégrale, qui peut s'écrire comme limite d'une sommation, c'est très intéressant :https://sites.google.com/site/rcorcs/posts/calculatingthepiconstantLe fichier "Pi comme intégrale" explique cette méthode utilisée dans cet article.

Tout d’abord, notez que C# peut utiliser le champ Math.PI du framework .NET :

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

La fonctionnalité intéressante ici est qu'il s'agit d'un double pleine précision que vous pouvez soit utiliser, soit comparer avec les résultats calculés.Les onglets de cette URL ont des constantes similaires pour C++, F# et Visual Basic.

Pour calculer plus de places, vous pouvez écrire votre propre code de précision étendue.Celui qui est rapide à coder et raisonnablement rapide et facile à programmer est :

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

Cette formule et bien d'autres, dont certaines qui convergent à des rythmes étonnamment rapides, comme 50 chiffres par terme, se trouvent chez Wolfram :

Formules Wolfram Pi

PI (π) peut être calculé en utilisant série infinie.Voici deux exemples :

Série Grégory-Leibniz :

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

Méthode C# :

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;
}

Série Nilakantha :

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

Méthode C# :

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;
}

Le paramètre d'entrée n pour les deux fonctions représente le nombre d’itérations.

La série Nilakantha, par rapport à la série Gregory-Leibniz, converge plus rapidement.Les méthodes peuvent être testées avec le code suivant :

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();
}

Le résultat suivant montre que la série Nilakantha renvoie six décimales correctes de PI avec cent itérations, tandis que la série Gregory-Leibniz renvoie cinq décimales correctes de PI avec un million d'itérations :

enter image description here

Mon code peut être testé >> ici

Voici une belle manière :Calculez une série de 1/x^2 pour x de 1 à ce que vous voulez – plus le nombre est grand, meilleur est le résultat du gâteau.Multipliez le résultat par 6 et par sqrt().Voici le code en c# (principal uniquement) :

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;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top