Quel est le moyen le plus rapide d'obtenir la valeur de ??

Les solutions sont les bienvenues dans toutes les langues. :-) Je cherche le moyen le plus rapide d'obtenir la valeur de?, Comme un défi personnel. Plus spécifiquement, j'utilise des méthodes qui n'impliquent pas l'utilisation de #define d constantes comme M_PI , ou le codage en dur du nombre.

Le programme ci-dessous teste les différentes façons dont je connais. La version d'assemblage en ligne est, en théorie, l'option la plus rapide, bien que clairement non portable; Je l'ai inclus comme référence pour comparer les autres versions. Dans mes tests, avec les built-ins, la version 4 * atan (1) est la plus rapide sur GCC 4.2, car elle plie automatiquement le atan (1) en une constante . Avec -fno-builtin spécifié, la version atan2 (0, -1) est la plus rapide.

Voici le programme de test principal ( pitimes.c ):

#include 
#include 
#include 

#define ITERS 10000000
#define TESTWITH(x) {                                                       \
    diff = 0.0;                                                             \
    time1 = clock();                                                        \
    for (i = 0; i < ITERS; ++i)                                             \
        diff += (x) - M_PI;                                                 \
    time2 = clock();                                                        \
    printf("%s\t=> %e, time => %f\n", #x, diff, diffclock(time2, time1));   \
}

static inline double
diffclock(clock_t time1, clock_t time0)
{
    return (double) (time1 - time0) / CLOCKS_PER_SEC;
}

int
main()
{
    int i;
    clock_t time1, time2;
    double diff;

    /* Warmup. The atan2 case catches GCC's atan folding (which would
     * optimise the ``4 * atan(1) - M_PI'' to a no-op), if -fno-builtin
     * is not used. */
    TESTWITH(4 * atan(1))
    TESTWITH(4 * atan2(1, 1))

#if defined(__GNUC__) && (defined(__i386__) || defined(__amd64__))
    extern double fldpi();
    TESTWITH(fldpi())
#endif

    /* Actual tests start here. */
    TESTWITH(atan2(0, -1))
    TESTWITH(acos(-1))
    TESTWITH(2 * asin(1))
    TESTWITH(4 * atan2(1, 1))
    TESTWITH(4 * atan(1))

    return 0;
}

Et le matériel d'assemblage en ligne ( fldpi.c ), notant qu'il ne fonctionnera que pour les systèmes x86 et x64:

double
fldpi()
{
    double pi;
    asm("fldpi" : "=t" (pi));
    return pi;
}

Et un script de construction qui construit toutes les configurations que je suis en train de tester ( build.sh ):

#!/bin/sh
gcc -O3 -Wall -c           -m32 -o fldpi-32.o fldpi.c
gcc -O3 -Wall -c           -m64 -o fldpi-64.o fldpi.c

gcc -O3 -Wall -ffast-math  -m32 -o pitimes1-32 pitimes.c fldpi-32.o
gcc -O3 -Wall              -m32 -o pitimes2-32 pitimes.c fldpi-32.o -lm
gcc -O3 -Wall -fno-builtin -m32 -o pitimes3-32 pitimes.c fldpi-32.o -lm
gcc -O3 -Wall -ffast-math  -m64 -o pitimes1-64 pitimes.c fldpi-64.o -lm
gcc -O3 -Wall              -m64 -o pitimes2-64 pitimes.c fldpi-64.o -lm
gcc -O3 -Wall -fno-builtin -m64 -o pitimes3-64 pitimes.c fldpi-64.o -lm

Mis à part les tests entre les différents drapeaux du compilateur (j'ai aussi comparé le 32 bits au 64 bits, parce que les optimisations sont différentes), j'ai aussi essayé de changer l'ordre des tests. La version de atan2 (0, -1) sort quand même la tête à chaque fois.

0
ajouté édité
Vues: 36
@Zeus Dans ce cas précis, ma question était en fait destinée à être une question de micro-optimisation «amusante» (qui, de nos jours, serait probablement mieux adaptée à Programming Puzzles & Code Golf ), mais la prémisse générale du" moyen le plus rapide de calculer pi "semblait être assez utile pour garder cette question ici. Donc, à un certain stade, je vais probablement réévaluer si je devrais accepter la meilleure réponse algorithmique (probablement celle de nlucaroni), sans se soucier de savoir si c'est lié à la micro-optimisation.
ajouté l'auteur Chris Jester-Young, source
@ HopelessN00b Dans le dialecte de l'anglais je parle, "optimisation" est orthographié avec un " s ", pas un" z "(qui se prononce comme" zed ", BTW, pas" zee ";-)). (Ce n'est pas la première fois que je dois revenir sur ce type d'édition, si vous regardez l'historique des critiques.)
ajouté l'auteur Chris Jester-Young, source
La réponse de nlucaroni a atteint 100 upvotes (félicitations), donc c'est probablement un bon point de le faire. Prendre plaisir! (Bien que, comme c'est le wiki de la communauté et tout, il ne génère aucun rep, donc même pas sûr si nlucaroni le remarquera.)
ajouté l'auteur Chris Jester-Young, source
ajouté l'auteur Chris Jester-Young, source
@erik: Toutes les langues n'ont pas de constante intégrée comme M_PI . J'essayais de trouver une façon "autoritaire" d'obtenir une valeur (en virgule flottante) de pi qui (en théorie) fonctionne à travers une variété de langages (et / ou leurs bibliothèques intégrées). Ma méthode préférée actuelle utilise atan2 (0, -1) , mais il existe peut-être de meilleurs moyens.
ajouté l'auteur Chris Jester-Young, source
@signonsridhar Non, nous parlons seulement de méthodes de calcul qui donnent exactement le même résultat que M_PI quand elles sont tronquées en double précision.
ajouté l'auteur Chris Jester-Young, source
Il doit y avoir un moyen de le faire en métaprogrammation C ++. Le temps d'exécution sera vraiment bon, mais le temps de compilation ne sera pas.
ajouté l'auteur David Thornley, source
Il n'y a qu'une solution qui est plus rapide que la constante pré-calculée PI: pré-calculer toutes les valeurs qui apparaissent dans les formules, par ex. Lorsque la circonférence nécessaire, vous pouvez pré-calculer 2 * PI au lieu de multiplier chaque fois que le PI par 2 en cours d'exécution.
ajouté l'auteur ern0, source
la question est: pourquoi ne voulez-vous pas utiliser une constante? par exemple. soit défini par une bibliothèque ou par vous-même? Le calcul Pi est un gaspillage de cycles CPU, car ce problème a été résolu à maintes reprises à un nombre de chiffres significatifs beaucoup plus élevé que nécessaire pour les calculs quotidiens
ajouté l'auteur Tilo, source
Pourquoi considérez-vous l'utilisation de atan (1) différente de l'utilisation de M_PI? Je comprendrais pourquoi vous voulez faire ceci si vous avez seulement utilisé des opérations arithmétiques, mais avec atan je ne vois pas le point.
ajouté l'auteur erikkallen, source
Cela devrait idéalement attirer l'attention de Mysticial, puisqu'il est le détenteur du record mondial de l'informatique pi au plus grand nombre de chiffres. stackoverflow.com/questions/14283270/…
ajouté l'auteur Team Upvote, source
@ ChrisJester-Young Nope. Ce n'est pas l'intention .. J'ai récemment commencé à lire plus dans les règles .. et pensé que je ferais ma part sur les threads que je visite pour rappeler aux utilisateurs qui pourraient avoir oublié coz de la longue durée. Je n'essaie absolument pas d'être une police ici. Excuses si je suis tombé sur impoli.
ajouté l'auteur Zeus, source
9801 / (1103? 8) .. donne six décimales .. c'est le moyen le plus rapide de calculer PI? = 3.14159273
ajouté l'auteur signonsridhar, source
@Chris Jester-Young Eh bien, je viens de voir une vidéo sur Ramanujan qui a donné cette façon de calculer PI. Donc je viens de le partager:>
ajouté l'auteur signonsridhar, source

20 Réponses

Voici une description générale d'une technique de calcul de pi que j'ai appris au lycée.

Je ne partage que cela parce que je pense qu'il est assez simple que n'importe qui puisse s'en souvenir, indéfiniment, et il vous enseigne le concept des méthodes de Monte-Carlo - qui sont des méthodes statistiques pour arriver à des réponses qui ne semblent pas immédiatement déductible à travers des processus aléatoires.

Dessinez un carré et inscrivez un quadrant (un quart de demi-cercle) à l'intérieur de ce carré (un quadrant dont le rayon est égal au côté du carré, afin qu'il remplisse le plus possible le carré)

Maintenant, lancez une fléchette sur le carré et notez où elle atterrit, c'est-à-dire choisissez un point aléatoire n'importe où dans le carré. Bien sûr, il a atterri à l'intérieur de la place, mais est-ce à l'intérieur du demi-cercle? Notez ce fait.

Répétez ce processus plusieurs fois - et vous trouverez qu'il ya un rapport entre le nombre de points à l'intérieur du demi-cercle et le nombre total de jetés, appelez ce ratio x.

Puisque la surface du carré est r fois r, vous pouvez déduire que la surface du demi-cercle est x fois r fois r (c'est-à-dire x fois r au carré). Donc x fois 4 vous donnera pi.

Ce n'est pas une méthode rapide à utiliser. Mais c'est un bon exemple d'une méthode de Monte Carlo. Et si vous regardez autour de vous, vous trouverez peut-être que de nombreux problèmes, en dehors de vos compétences de calcul, peuvent être résolus par de telles méthodes.

0
ajouté
C'est la méthode que nous avons utilisée pour calculer Pi dans un projet java à l'école. J'ai juste utilisé un randomiseur pour trouver les coordonnées x, y et plus nous avons jeté de «fléchettes» plus nous sommes arrivés à Pi.
ajouté l'auteur Jeff Keslinke, source

Si par le plus rapide, vous voulez dire le plus rapide pour taper le code, voici la solution golfscript :

;''6666,-2%{2+.2/@*\/10.3??2*+}*`1000<~\;
0
ajouté

La méthode de Monte-Carlo , comme mentionné, applique de très bons concepts mais ce n'est clairement pas le plus rapide - pas par un tir de loin, pas par une utilité raisonnable. En outre, tout dépend du type de précision que vous recherchez. Le pi le plus rapide que je connaisse est celui des chiffres codés en dur. En regardant Pi et Pi [PDF] , il y a beaucoup de formules.

Voici une méthode qui converge rapidement (~ 14digits par itération). L'application la plus rapide actuellement, PiFast , utilise cette formule avec la FFT . Je vais juste écrire la formule, puisque le code est simple. Cette formule a été presque trouvée par Ramanujan et découverte par Chudnovsky . C'est en fait comment il a calculé plusieurs milliards de chiffres du nombre - ce n'est donc pas une méthode à ignorer. La formule va déborder rapidement puisque nous divisons les factorielles, il serait alors avantageux de retarder ce calcul pour supprimer les termes.

entrer la description de l'image ici

entrer la description de l'image ici

où,

entrez la description de l'image ici

Ci-dessous se trouve le algorithme de Brent? Salamine . Wikipedia mentionne que lorsque a et b sont «assez proches» alors (a + b) ^ 2 / 4t sera une approximation de pi. Je ne suis pas sûr de ce que 'assez proche' signifie, mais de mes tests, une itération a 2digits, deux ont 7, et trois ont 15, bien sûr c'est avec des doubles, donc il pourrait avoir une erreur basée sur sa représentation et le ' vrai calcul pourrait être plus précis.

let pi_2 iters =
    let rec loop_ a b t p i =
        if i = 0 then a,b,t,p
        else
            let a_n = (a +. b) /. 2.0 
            and b_n = sqrt (a*.b)
            and p_n = 2.0 *. p in
            let t_n = t -. (p *. (a -. a_n) *. (a -. a_n)) in
            loop_ a_n b_n t_n p_n (i - 1)
    in 
    let a,b,t,p = loop_ (1.0) (1.0 /. (sqrt 2.0)) (1.0/.4.0) (1.0) iters in
    (a +. b) *. (a +. b) /. (4.0 *. t)

Enfin, que diriez-vous du pi golf (800 chiffres)? 160 caractères!

int a=10000,b,c=2800,d,e,f[2801],g;main(){for(;b-c;)f[b++]=a/5;for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)for(b=c;d+=f[b]*a,f[b]=d%--g,d/=g--,--b;d*=b);}
0
ajouté
En supposant que vous essayez d'implémenter le premier vous-même, sqr (k3) ne serait-il pas un problème? Je suis à peu près sûr que cela aboutirait à un nombre irrationnel que vous devrez estimer (IIRC, toutes les racines qui ne sont pas des nombres entiers sont irrationnelles). Tout le reste semble assez simple si vous utilisez l'arithmétique de précision infinie, mais cette racine carrée est un briseur d'affaire. Le second comprend également un sqrt.
ajouté l'auteur Bill K, source
D'après mon expérience, «assez proche» signifie généralement qu'il y a une approximation de la série Taylor.
ajouté l'auteur Stephen, source

J'aime vraiment ce programme, qui se rapproche de pi en regardant sa propre zone :-)

IOCCC 1988: westley.c

#define _ -F<00||--F-OO--;
int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()
{
            _-_-_-_
       _-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_
            _-_-_-_
}
0
ajouté
Si vous remplacez _ avec -F <00 || --F-OO-- cela devrait être plus facile à suivre :-)
ajouté l'auteur Pat, source
Ce programme était génial en 1998, mais a été brisé parce que les préprocesseurs modernes sont plus libéraux avec l'insertion d'espaces autour des expansions de macro pour empêcher de telles choses de fonctionner. C'est une relique, malheureusement.
ajouté l'auteur Chris Lutz, source
il imprime 0.25 ici -.-
ajouté l'auteur Johannes Schaub - litb, source
@Pat si vous vous plaignez pourquoi je l'ai édité parce que j'ai vu cette réponse dans la file d'attente LQP stackoverflow.com/review/low -quality-posts / 16750528 , donc pour éviter la suppression, j'ai ajouté le code dans le lien vers la réponse.
ajouté l'auteur Petter Friberg, source
Passez - traditional-cpp à cpp pour obtenir le comportement voulu.
ajouté l'auteur Nietzche-jou, source
ou, si vous remplacez _ par "if (le caractère précédent est '-') {OO--;} F--;"
ajouté l'auteur FryGuy, source

Dans l'ancien temps, avec de petites tailles de mots et des opérations à virgule flottante lentes ou inexistantes, nous avions l'habitude de faire des choses comme ceci:

/* Return approximation of n * PI; n is integer */
#define pi_times(n) (((n) * 22) / 7)

Pour les applications qui ne nécessitent pas beaucoup de précision (jeux vidéo, par exemple), c'est très rapide et assez précis.

0
ajouté
Pour plus de précision, utilisez 355/113 . Très précis pour la taille des nombres impliqués.
ajouté l'auteur David Thornley, source
Juste par curiosité: 22/7 est 3 + 1/7
ajouté l'auteur Agnius Vasiliauskas, source

La formule BBP vous permet de calculer le nième chiffre - en base 2 (ou 16 ) - sans avoir à se préoccuper des chiffres n-1 précédents en premier :)

0
ajouté

Cette version (en Delphi) n'a rien de spécial, mais elle est au moins plus rapide que la version Nick Hodge posté sur son blog :). Sur ma machine, il faut environ 16 secondes pour faire un milliard d'itérations, ce qui donne une valeur de 3.14159265 25879 (la partie précise est en gras).

program calcpi;

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
  start, finish: TDateTime;

function CalculatePi(iterations: integer): double;
var
  numerator, denominator, i: integer;
  sum: double;
begin
  {
  PI may be approximated with this formula:
  4 * (1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 .......)
  //}
  numerator := 1;
  denominator := 1;
  sum := 0;
  for i := 1 to iterations do begin
    sum := sum + (numerator/denominator);
    denominator := denominator + 2;
    numerator := -numerator;
  end;
  Result := 4 * sum;
end;

begin
  try
    start := Now;
    WriteLn(FloatToStr(CalculatePi(StrToInt(ParamStr(1)))));
    finish := Now;
    WriteLn('Seconds:' + FormatDateTime('hh:mm:ss.zz',finish-start));
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.
0
ajouté

Si cet article est vrai, alors le algorithme que Bellard a créé pourrait être l'un des plus rapides disponibles. Il a créé pi à 2,7 milliards de chiffres en utilisant un PC de bureau!

...and he has published his work here

Bon travail Bellard, Vous êtes un pionnier!

http://www.theregister.co.uk/2010/01/06/ very_long_pi /

0
ajouté
Bellard a été le pionnier de nombreuses façons ... d'abord, il y avait LZEXE, probablement le premier compresseur exécutable (pensez à ce que fait UPX, puis revenez dans le temps des années 80), et bien sûr maintenant, QEMU et FFMPEG sont largement utilisés . Oh, et son entrée IOCCC .... :-P
ajouté l'auteur Chris Jester-Young, source

Si vous voulez utiliser une approximation, 355/113 est bon pour 6 chiffres décimaux, et a l'avantage d'être utilisable avec des expressions entières. Ce n'est pas aussi important ces jours-ci, car "coprocesseur mathématique à virgule flottante" a cessé d'avoir un sens, mais c'était assez important une fois.

0
ajouté

Dans l'intérêt de l'exhaustivité, une version de modèle C ++ qui, pour une construction optimisée, calculera PI au moment de la compilation et s'introduira dans une seule valeur.

#include 

template
struct sign
{
    enum {value = (I % 2) == 0 ? 1 : -1};
};

template
struct pi_calc
{
    inline static double value ()
    {
        return (pi_calc::value() + pi_calc::value ()) / 2.0;
    }
};

template
struct pi_calc<0, J>
{
    inline static double value ()
    {
        return (sign::value * 4.0) / (2.0 * J + 1.0) + pi_calc<0, J-1>::value ();
    }
};


template<>
struct pi_calc<0, 0>
{
    inline static double value ()
    {
        return 4.0;
    }
};

template
struct pi
{
    inline static double value ()
    {
        return pi_calc::value ();
    }
};

int main ()
{
    std::cout.precision (12);

    const double pi_value = pi<10>::value ();

    std::cout << "pi ~ " << pi_value << std::endl;

    return 0;
}

Note for I > 10, optimised builds can be slow, likewise for non-optimised runs. For 12 iterations I believe there are around 80k calls to value() (in the absence of memoisation).

0
ajouté
@ sebastião-miranda La formule de Leibniz , avec une accélération moyenne, améliore la convergence. pi_calc <0, J> calcule chaque terme successif à partir de la formule et le non spécialisé pi_calc calcule la moyenne.
ajouté l'auteur jon-hanson, source
Eh bien, c'est exact à 9dp. Êtes-vous en train de vous opposer à quelque chose ou simplement de faire une observation?
ajouté l'auteur jon-hanson, source
Je cours ceci et je reçois "pi ~ 3.14159265383"
ajouté l'auteur maxwellb, source
Quel est le nom de l'algorithme utilisé ici pour calculer PI?
ajouté l'auteur Sebastião Miranda, source

Calculer? de la zone du cercle :-)

<div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code">

<input id="range" type="range" min="10" max="960" value="10" step="50" oninput="calcPi()">

<div id="cont"></div> <script> function generateCircle(width) { var c = width/2; var delta = 1.0; var str = ""; var xCount = 0; for (var x=0; x <= width; x++) { for (var y = 0; y <= width; y++) { var d = Math.sqrt((x-c)*(x-c) + (y-c)*(y-c)); if (d > (width-1)/2) { str += '.'; } else { xCount++; str += 'o'; } str += " " } str += "\n"; } var pi = (xCount * 4) / (width * width); return [str, pi]; } function calcPi() { var e = document.getElementById("cont"); var width = document.getElementById("range").value; e.innerHTML = "

Generating circle...

";
    setTimeout(function() {
        var circ = generateCircle(width);
        e.innerHTML  = "
" + "? = " + circ[1].toFixed(2) + "\n" + circ[0] +"
";
    }, 200);
}
calcPi();
</script>
</div> </div>

0
ajouté

Les réponses suivantes expliquent précisément comment le faire le plus rapidement possible - avec le moins d'effort de calcul . Même si vous n'aimez pas la réponse, vous devez admettre que c'est en effet le moyen le plus rapide de obtenir la valeur de PI.

La façon la plus rapide d'obtenir la valeur de Pi est:

  1. a choisi votre langage de programmation favori
  2. charger sa bibliothèque de maths
  3. et trouve que Pi est déjà défini là !! prêt à l'utiliser ..

dans le cas où vous n'avez pas une bibliothèque de mathématiques à portée de main.

le DEUXIEME PLUS RAPIDE (solution plus universelle) est:

cherchez Pi sur Internet, p. ici:

http://www.eveandersson.com/pi/digits/1000000 (1 million digits .. what's your floating point precision? )

ou ici:

http://3.141592653589793238462643383279502884197169399375105820974944592.com/

ou ici:

http://en.wikipedia.org/wiki/Pi

Il est très rapide de trouver les chiffres dont vous avez besoin pour l'arithmétique de précision que vous souhaitez utiliser, et en définissant une constante, vous pouvez vous assurer que vous ne perdez pas de temps processeur précieux.

Ce n'est pas seulement une réponse en partie humoristique, mais en réalité, si quelqu'un devait aller de l'avant et calculer la valeur de Pi dans une application réelle ... ce serait une perte de temps processeur importante, n'est-ce pas? Au moins, je ne vois pas de véritable application pour essayer de recalculer cela.

Cher Modérateur: veuillez noter que le PO a demandé: "Le moyen le plus rapide d'obtenir la valeur de PI"

0
ajouté

Si vous voulez calculer une approximation de la valeur de? (pour une raison quelconque), vous devriez essayer un algorithme d'extraction binaire. Amélioration de Bellard de BBP donne PI en O (N ^ 2).


Si vous voulez obtenir une approximation de la valeur de? faire des calculs, alors:

PI = 3.141592654

Certes, ce n'est qu'une approximation, et pas tout à fait exact. Il est éteint par un peu plus de 0.00000000004102. (quatre dix-trillions, environ 4 / 10,000,000,000 ).


Si vous voulez faire math avec?, Alors procurez-vous un crayon et du papier ou un paquet d'algèbre informatique, et utilisez la valeur exacte de?.

Si vous voulez vraiment une formule, celle-ci est amusante:

? = - i ln (-1)

0
ajouté
Votre formule dépend de la façon dont vous définissez ln dans le plan complexe. Il doit être non contigu sur une ligne dans le plan complexe, et il est assez courant que cette ligne soit l'axe réel négatif.
ajouté l'auteur erikkallen, source

Je suis juste tombé sur celui qui devrait être ici pour être complet:

calculer PI dans Piet

Il a la propriété plutôt sympa que la précision peut être améliorée en agrandissant le programme.

Here's some insight into the language itself

0
ajouté

Calculer PI à la compilation avec D.

(Copié de DSource.org )

/** Calculate pi at compile time
 *
 * Compile with dmd -c pi.d
 */
module calcpi;

import meta.math;
import meta.conv;

/** real evaluateSeries!(real x, real metafunction!(real y, int n) term)
 *
 * Evaluate a power series at compile time.
 *
 * Given a metafunction of the form
 *  real term!(real y, int n),
 * which gives the nth term of a convergent series at the point y
 * (where the first term is n==1), and a real number x,
 * this metafunction calculates the infinite sum at the point x
 * by adding terms until the sum doesn't change any more.
 */
template evaluateSeries(real x, alias term, int n=1, real sumsofar=0.0)
{
  static if (n>1 && sumsofar == sumsofar + term!(x, n+1)) {
     const real evaluateSeries = sumsofar;
  } else {
     const real evaluateSeries = evaluateSeries!(x, term, n+1, sumsofar + term!(x, n));
  }
}

/*** Calculate atan(x) at compile time.
 *
 * Uses the Maclaurin formula
 *  atan(z) = z - z^3/3 + Z^5/5 - Z^7/7 + ...
 */
template atan(real z)
{
    const real atan = evaluateSeries!(z, atanTerm);
}

template atanTerm(real x, int n)
{
    const real atanTerm =  (n & 1 ? 1 : -1) * pow!(x, 2*n-1)/(2*n-1);
}

/// Machin's formula for pi
/// pi/4 = 4 atan(1/5) - atan(1/239).
pragma(msg, "PI = " ~ fcvt!(4.0 * (4*atan!(1/5.0) - atan!(1/239.0))) );
0
ajouté
Malheureusement, les tangentes sont des arctangents basés sur pi, invalidant quelque peu ce calcul.
ajouté l'auteur Grant Johnson, source

Il y a en fait tout un livre dédié (entre autres) aux méthodes fast pour le calcul de \ pi: 'Pi et l'AGM', par Jonathan et Peter Borwein ( disponible sur Amazon ).

J'ai beaucoup étudié l'AGA et les algorithmes associés: c'est assez intéressant (bien que parfois non trivial).

Notez que pour implémenter les algorithmes les plus modernes pour calculer \ pi, vous aurez besoin d'une bibliothèque arithmétique multiprécision ( GMP est un bon choix , même si cela fait un moment que je ne l'ai pas utilisé pour la dernière fois).

La complexité temporelle des meilleurs algorithmes est dans O (M (n) log (n)), où M (n) est la complexité temporelle pour la multiplication de deux entiers de n bits (M (n) = O (n log (n) log (log (n))) en utilisant des algorithmes basés sur FFT, qui sont généralement nécessaires lors du calcul des chiffres de \ pi, et un tel algorithme est implémenté dans GMP).

Notez que même si les mathématiques derrière les algorithmes peuvent ne pas être triviales, les algorithmes eux-mêmes sont généralement quelques lignes de pseudo-code, et leur implémentation est généralement très simple (si vous choisissez de ne pas écrire votre propre arithmétique multiprécision :-)).

0
ajouté

C'est une méthode "classique", très facile à mettre en œuvre. Cette implémentation, en python (langage pas si rapide) le fait:

from math import pi
from time import time


precision = 10**6 # higher value -> higher precision
                  # lower  value -> higher speed

t = time()

calc = 0
for k in xrange(0, precision):
    calc += ((-1)**k) / (2*k+1.)
calc *= 4. # this is just a little optimization

t = time()-t

print "Calculated: %.40f" % calc
print "Costant pi: %.40f" % pi
print "Difference: %.40f" % abs(calc-pi)
print "Time elapsed: %s" % repr(t)

Vous pouvez trouver plus d'informations ici .

Quoi qu'il en soit, le moyen le plus rapide d'obtenir une valeur précise de pi en python est:

from gmpy import pi
print pi(3000) # the rule is the same as 
               # the precision on the previous code

voici la source de la méthode gmpy pi, je ne pense pas que le code soit aussi utile que le commentaire dans ce cas:

static char doc_pi[]="\
pi(n): returns pi with n bits of precision in an mpf object\n\
";

/* This function was originally from netlib, package bmp, by
 * Richard P. Brent. Paulo Cesar Pereira de Andrade converted
 * it to C and used it in his LISP interpreter.
 *
 * Original comments:
 * 
 *   sets mp pi = 3.14159... to the available precision.
 *   uses the gauss-legendre algorithm.
 *   this method requires time o(ln(t)m(t)), so it is slower
 *   than mppi if m(t) = o(t**2), but would be faster for
 *   large t if a faster multiplication algorithm were used
 *   (see comments in mpmul).
 *   for a description of the method, see - multiple-precision
 *   zero-finding and the complexity of elementary function
 *   evaluation (by r. p. brent), in analytic computational
 *   complexity (edited by j. f. traub), academic press, 1976, 151-176.
 *   rounding options not implemented, no guard digits used.
*/
static PyObject *
Pygmpy_pi(PyObject *self, PyObject *args)
{
    PympfObject *pi;
    int precision;
    mpf_t r_i2, r_i3, r_i4;
    mpf_t ix;

    ONE_ARG("pi", "i", &precision);
    if(!(pi = Pympf_new(precision))) {
        return NULL;
    }

    mpf_set_si(pi->f, 1);

    mpf_init(ix);
    mpf_set_ui(ix, 1);

    mpf_init2(r_i2, precision);

    mpf_init2(r_i3, precision);
    mpf_set_d(r_i3, 0.25);

    mpf_init2(r_i4, precision);
    mpf_set_d(r_i4, 0.5);
    mpf_sqrt(r_i4, r_i4);

    for (;;) {
        mpf_set(r_i2, pi->f);
        mpf_add(pi->f, pi->f, r_i4);
        mpf_div_ui(pi->f, pi->f, 2);
        mpf_mul(r_i4, r_i2, r_i4);
        mpf_sub(r_i2, pi->f, r_i2);
        mpf_mul(r_i2, r_i2, r_i2);
        mpf_mul(r_i2, r_i2, ix);
        mpf_sub(r_i3, r_i3, r_i2);
        mpf_sqrt(r_i4, r_i4);
        mpf_mul_ui(ix, ix, 2);
        /* Check for convergence */
        if (!(mpf_cmp_si(r_i2, 0) && 
              mpf_get_prec(r_i2) >= (unsigned)precision)) {
            mpf_mul(pi->f, pi->f, r_i4);
            mpf_div(pi->f, pi->f, r_i3);
            break;
        }
    }

    mpf_clear(ix);
    mpf_clear(r_i2);
    mpf_clear(r_i3);
    mpf_clear(r_i4);

    return (PyObject*)pi;
}

EDIT: I had some problem with cut and paste and identation, anyway you can find the source here.

0
ajouté

La méthode de Brent publiée ci-dessus par Chris est très bonne; Brent est généralement un géant dans le domaine de l'arithmétique de précision arbitraire.

Si tout ce que vous voulez est le Nième chiffre, le célèbre Formule BBP est utile en hexadécimal

0
ajouté
La méthode Brent n'a pas été postée par moi; Il a été posté par Andrea, et je viens d'être la dernière personne qui a édité le poste. :-) Mais je suis d'accord, ce post mérite une upvote.
ajouté l'auteur Chris Jester-Young, source

Avec des doubles:

4.0 * (4.0 * Math.Atan(0.2) - Math.Atan(1.0 / 239.0))

Ce sera précis jusqu'à 14 décimales, assez pour remplir un double (l'inexactitude est probablement due au fait que le reste des décimales dans les tangentes d'arc sont tronquées).

Aussi Seth, c'est 3.14159265358979323846 3 , pas 64.

0
ajouté

Utilisez la formule Machin

176 * arctan (1/57) + 28 * arctan (1/239) - 48 * arctan (1/682) + 96 * arctan(1/12943) 

[; \left( 176 \arctan \frac{1}{57} + 28 \arctan \frac{1}{239} - 48 \arctan \frac{1}{682} + 96 \arctan \frac{1}{12943}\right) ;], for you TeX the World people.

Implémenté dans Scheme, par exemple:

(+ (- (+ (* 176 (atan (/ 1 57))) (* 28 (atan (/ 1 239)))) (* 48 (atan (/ 1 682)))) (* 96 (atan (/ 1 12943))))

0
ajouté