Code Golf: formule Leibniz pour Pi

j'ai récemment posté une de mes questions préférées de codage de tableau blanc d'entrevue dans Quelle est votre opinion de programmation plus controversée ", qui est d'écrire une fonction qui calcule Pi en utilisant la formule de Leibniz .

il peut être abordé dans un certain nombre de façons différentes, et la condition de sortie prend un peu de réflexion, donc j'ai pensé qu'il pourrait faire une question de golf de code intéressant. Plus court le code gagne!

étant donné que Pi peut être estimé à l'aide de la fonction 4 * (1 - 1/3 + 1/5 - 1/7 + ...) avec plus de termes donnant une plus grande précision, écrire une fonction qui calcule Pi à l'intérieur de 0.00001.

Edit: 3 Jan 2008

comme suggéré dans les commentaires j'ai changé la condition de sortie pour être à l'intérieur de 0.00001 comme c'est ce que je voulais vraiment dire (une précision de 5 décimales est beaucoup plus difficile en raison de l'arrondissement et donc je ne voudrais pas demander cela dans une interview, alors que dans 0.00001 est un plus facile à comprendre et mettre en œuvre condition de sortie).

aussi, pour répondre aux commentaires, je suppose que mon intention était que la solution devrait calculer le nombre d'itérations, ou vérifier quand il a fait assez, mais il n'y a rien pour vous empêcher de pré-calculer le nombre d'itérations et l'utilisation de ce nombre. J'ai vraiment posé la question par intérêt pour voir ce que les gens viendrait avec.

31
demandé sur Greg Beech 2009-01-02 20:42:45

30 réponses

J, 14 chars

4*-/%>:+:i.1e6

explication

  • 1e6 est le numéro 1 suivi de 6 zéros (1000000).
  • i.y génère le premier y nombres non négatifs.
  • +: est une fonction qui double chaque élément dans la liste argument.
  • >: est une fonction qui augmente d'un élément par élément dans l'argument list.

ainsi, l'expression >:+:i.1e6 génère le premier million de nombres impairs:

1 3 5 7 ...

  • % est l'opérateur réciproque (le numérateur " 1 " peut être omis).
  • -/ ne une autre somme de chaque élément dans la liste d'argument.

ainsi, l'expression -/%>:+:i.1e6 génère la somme alternative des réciproques du premier million de nombres impairs:

1 - 1/3 + 1/5 - 1/7 + ...

  • 4* est une multiplication par quatre. Si vous multipliez par quatre précédentes somme, vous avez π.

C'est ça! J est un langage puissant pour mathématique.


modifier : depuis la génération 9! (362880) les termes pour la somme alternative est suffisante pour avoir 5 précision décimale, et puisque la formule de Leibniz peut être écrite aussi de cette façon:

4 - 4/3 + 4/5 - 4/7 + ...

...vous pouvez écrire une courte 12 caractères version du programme:

-/4%>:+:i.9!
61
répondu friol 2010-02-16 13:33:00

langue: Brainfuck, nombre de caractères: 51/59

ça compte? = ]

comme il n'y a pas de nombres à virgule flottante à Brainfuck, il était assez difficile de faire fonctionner correctement les divisions. Grr.

sans newline (51):

+++++++[>+++++++<-]>++.-----.+++.+++.---.++++.++++.

avec newline (59):

+++++++[>+++++++>+<<-]>++.-----.+++.+++.---.++++.++++.>+++.
37
répondu strager 2009-08-21 15:48:07

Perl

26 caractères

26 seulement la fonction, 27, de calculer, de 31 à imprimer. Des commentaires à cette réponse .

sub _{$-++<1e6&&4/$-++-&_}       # just the sub
sub _{$-++<1e6&&4/$-++-&_}_      # compute
sub _{$-++<1e6&&4/$-++-&_}say _  # print

28 caractères

28 juste calcul, 34 à imprimer. D'après les commentaires. Notez que cette version ne peut pas utiliser "say".

$.=.5;$\=2/$.++-$\for 1..1e6        # no print
$.=.5;$\=2/$.++-$\for$...1e6;print  # do print, with bonus obfuscation

36 caractères

36 juste calcul, 42 à imprimer. Hudson prendre à le réarrangement de dreeves, d'après les commentaires.

$/++;$\+=8/$//($/+2),$/+=4for$/..1e6
$/++;$\+=8/$//($/+2),$/+=4for$/..1e6;print

à propos du compte d'itération: en ce qui concerne mes souvenirs mathématiques, 400000 est assez pour être précis à 0.00001. Mais un million (ou aussi bas que 8e5) fait en fait l'expansion décimale correspondent en fait 5 places fractionnaires, et c'est le même nombre de caractères donc j'ai gardé cela.

24
répondu JB. 2017-05-23 12:08:35

Ruby, 33 caractères

(0..1e6).inject{|a,b|2/(0.5-b)-a}
23
répondu Zach Langley 2009-01-05 19:39:39

une Autre version de C#:

(60 caractères)

4*Enumerable.Range(0, 500000).Sum(x => Math.Pow(-1, x)/(2*x + 1));  // = 3,14159
20
répondu CMS 2009-01-02 23:41:19

52 caractères dans Python :

print 4*sum(((-1.)**i/(2*i+1)for i in xrange(5**8)))

(51 tomber le 'x' de xrange.)

36 chars en Octave (ou Matlab):

l=0:5^8;disp((-1).^l*(4./(2.*l+1))')

(exécuter" format long; " pour afficher tous les chiffres significatifs.

octave:5> l=0:5^8;(-1).^l*(4./(2.*l+1))'
ans = 3.14159009359631
14
répondu Federico A. Ramponi 2009-10-15 10:32:58

Oracle SQL 73 chars

select -4*sum(power(-1,level)/(level*2-1)) from dual connect by level<1e6
13
répondu tuinstoel 2009-10-15 10:33:26

langue: C, nombre de caractères: 71

float p;main(i){for(i=1;1E6/i>5;i+=2)p-=(i%4-2)*4./i;printf("%g\n",p);}

langue: C99, nombre de caractères: 97 (y compris la nouvelle ligne obligatoire)

#include <stdio.h>
float p;int main(){for(int i=1;1E6/i>5;i+=2)p-=(i%4-2)*4./i;printf("%g\n",p);}

je dois noter que les versions ci-dessus (qui sont les mêmes) garder la trace de savoir si une itération supplémentaire affecterait le résultat du tout. Elle effectue donc un nombre minimal d'opérations. Pour ajouter d'autres chiffres, remplacer 1E6 par 1E(num_digits+1) ou 4E5 avec 4E(num_digits) (selon la version). Pour les programmes complets, il faudra peut-être remplacer %g . float peut être changé pour double .

langue: C, nombre de caractères: 67 (Voir notes)

double p,i=1;main(){for(;i<1E6;i+=4)p+=8/i/(i+2);printf("%g\n",p);}

Cette version utilise une version modifiée de posté algorithme utilisé par certains autres réponses. Aussi, il n'est pas aussi simple/efficace que les deux premières solutions, car elle oblige 100 000 itérations au lieu de détecter quand les itérations deviennent insignifiantes.

langue: C, nombre de caractères: 24 (tricherie )

main(){puts("3.14159");}

ne fonctionne pas avec des chiffres > 6, cependant.

10
répondu strager 2009-01-03 08:58:03

Haskell

j'ai réduit à 34 caractères:

foldl subtract 4$map(4/)[3,5..9^6]

cette expression fournit 3.1415964169355556 lorsqu'elle est évaluée.

Edit: voici une version un peu plus courte (à 33 caractères) qui utilise foldl1 au lieu de foldl:

foldl1 subtract$map(4/)[1,3..9^6]

Edit 2: 9^6 au lieu de 10^6. On doit être économique;)

Edit 3: remplacé par foldl 'et foldl1' par foldl et foldl1 respectivement-à la suite D'Edit 2, il ne déborde plus. Merci à ShreevatsaR de l'avoir remarqué.

10
répondu Gracenotes 2009-01-05 09:53:28

23 chars en MATLAB:

a=1e6;sum(4./(1-a:4:a))
10
répondu gnovice 2009-01-22 19:47:57

F# :

tentative #1:

let pi = 3.14159

de la Tricherie? Non, son gagner avec style!

tentative #2:


let pi =
    seq { 0 .. 100 }
    |> Seq.map (fun x -> float x)
    |> Seq.fold (fun x y -> x + (Math.Pow(-1.0, y)/(2.0 * y + 1.0))) 0.0
    |> (fun x -> x * 4.0)

ce N'est pas aussi compact qu'il pourrait l'être, mais assez idiomatique F#.

9
répondu Juliet 2009-10-15 10:34:01

common lisp, 55 chars.

(loop for i from 1 upto 4e5 by 4 sum (/ 8d0 i (+ i 2)))
7
répondu user49117 2009-01-05 03:53:43

Mathematica, 27 caractères (probablement aussi bas que 26, ou aussi haut que 33)

NSum[8/i/(i+2),{i,1,9^9,4}]

si vous supprimez le" N " initial alors il renvoie la réponse comme une (énorme) fraction.

si C'est tromper que Mathematica n'a pas besoin d'une déclaration d'impression pour produire son résultat, alors préparez " Print@ " pour un total de 33 caractères.

NB:

si c'est tromper le nombre de termes, alors je ne pense pas la réponse n'a pas encore obtenu ce droit. Vérifier quand le terme courant est en dessous d'un certain seuil n'est pas mieux que le codage dur du nombre de termes. Ce n'est pas parce que le terme courant ne change que le 6ème ou le 7ème chiffre que la somme de plusieurs termes subséquents ne changera pas le 5ème chiffre.

6
répondu dreeves 2009-01-03 06:01:28

utilisant la formule pour le terme d'erreur dans une série alternative (et donc le nombre nécessaire d'itérations pour atteindre la précision désirée n'est pas codé dur dans le programme):

public static void Main(string[] args) {
    double tolerance = 0.000001;
    double piApproximation = LeibnizPi(tolerance);
    Console.WriteLine(piApproximation);
}

private static double LeibnizPi(double tolerance) {
    double quarterPiApproximation = 0;

    int index = 1;
    double term;
    int sign = 1;
    do {
        term = 1.0 / (2 * index - 1);
        quarterPiApproximation += ((double)sign) * term;
        index++;
        sign = -sign;
    } while (term > tolerance);

    return 4 * quarterPiApproximation;
}
5
répondu Jason 2009-01-03 03:10:18

C#:

public static double Pi()
{
    double pi = 0;
    double sign = 1;
    for (int i = 1; i < 500002; i += 2)
    {
        pi += sign / i;
        sign = -sign;
    }
    return 4 * pi;
}
4
répondu Darin Dimitrov 2009-01-02 18:16:11

Perl:

$i+=($_&1?4:-4)/($_*2-1)for 1..1e6;print$i

pour un total de 42 caractères.

4
répondu Learning 2009-01-02 18:30:27

Ruby, 41 chars (utilisant irb):

s=0;(3..3e6).step(4){|i|s+=8.0/i/(i-2)};s

Ou un peu plus, non-rir version:

s=0;(3..3e6).step(4){|i|s+=8.0/i/(i-2)};p s

C'est un Leibniz modifié:

  1. combinent des paires de termes. Cela vous donne 2/3 + 2/35 + 2/99 + ...
  2. Pi devient 8 * (1/(1 * 3) + 1/(5 * 7) + 1/(9 * 11) + ...)
4
répondu zenazn 2009-01-02 19:37:42

F# (Mode Interactif) (59 Caractères)

{0.0..1E6}|>Seq.fold(fun a x->a+ -1.**x/(2.*x+1.))0.|>(*)4.

(donne un avertissement mais omet les moulages)

4
répondu David Klein 2010-12-27 23:10:18

Voici une solution pour les oreillons.

pi(N)
 N X,I
 S X=1 F I=3:4:N-2 S X=X-(1/I)+(1/(I+2))
 Q 4*X

le paramètre N indique le nombre de fractions répétées à utiliser. C'est-à-dire, si vous passez dans 5 il évaluera 4 * (1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11)

certains tests empiriques ont montré que N=272241 est la valeur la plus basse qui donne une valeur correcte de 3,14159 lorsqu'elle est tronquée à 5 points décimaux. Vous devez aller à n = 852365 pour obtenir une valeur qui tourne à 3.14159.

3
répondu Clayton 2009-01-02 18:52:42

C# à l'aide de bloc itérateur:

static IEnumerable<double> Pi()
{
    double i = 4, j = 1, k = 4;
    for (;;)
    {
        yield return k;
        k += (i *= -1) / (j += 2);
    }
}
3
répondu dalle 2009-01-03 09:00:31

pour mémoire, cette implémentation de schéma a 95 caractères ignorant les espaces vides.

(define (f)
  (define (p a b)
    (if (> a b)
      0
      (+ (/ 1.0 (* a (+ a 2))) (p (+ a 4) b))))
  (* 8 (p 1 1e6)))
3
répondu Alan 2009-01-04 06:33:17

Javascript:

a=0,b=-1,d=-4,c=1e6;while(c--)a+=(d=-d)/(b+=2)

en javascript. 51 caractères. De toute évidence ne va pas gagner, mais hein. : P

Edit -- mis à jour à 46 caractères maintenant, grâce à Strager. :)


mise à jour (30 mars 2010)

a plus rapide (précis seulement à 5 décimales) 43 caractère version par David Murdoch

for(a=0,b=1,d=4,c=~4e5;++c;d=-d)a-=d/(b-=2)
3
répondu David Murdoch 2017-05-23 10:27:52

Voici une réponse récursive en utilisant C#. Il ne fonctionnera qu'avec le x64 JIT en mode Release car c'est le seul JIT qui applique l'optimisation tail-call, et comme la série converge si lentement, il en résultera un StackOverflowException sans lui.

ce serait bien d'avoir la fonction IteratePi comme lambda anonyme, mais comme c'est auto-récursif nous devrions commencer à faire toutes sortes de choses horribles avec des combinateurs Y donc je l'ai laissé comme une fonction séparée.

public static double CalculatePi()
{
    return IteratePi(0.0, 1.0, true);
}

private static double IteratePi(double result, double denom, bool add)
{
    var term = 4.0 / denom;
    if (term < 0.00001) return result;    
    var next = add ? result + term : result - term;
    return IteratePi(next, denom + 2.0, !add);
}
2
répondu Greg Beech 2009-01-02 17:46:29

la plupart des réponses actuelles supposent qu'ils obtiendront une précision de 5 chiffres à l'intérieur d'un certain nombre d'itérations et ce nombre est codé en dur dans le programme. Ma compréhension de la question était que le programme lui-même est censé comprendre quand il a une réponse précise à 5 chiffres et s'arrêter là. Dans cette hypothèse, voici ma solution. Je n'ai pas pris la peine de minimiser le nombre de caractères car il n'y a aucun moyen de rivaliser avec certaines des réponses déjà là, donc je j'ai pensé le rendre lisible à la place. :)

    private static double GetPi()
    {
        double acc = 1, sign = -1, lastCheck = 0;

        for (double div = 3; ; div += 2, sign *= -1)
        {
            acc += sign / div;

            double currPi = acc * 4;
            double currCheck = Math.Round(currPi, 5);

            if (currCheck == lastCheck)
                return currPi;

            lastCheck = currCheck;
        }
    }
2
répondu EMP 2009-01-03 03:09:35

langue: C99 (retour implicite 0), Nombre de caractères: 99 (95 + 4 espaces requis)

sortie dépend de la valeur actuelle, et non pas sur un fixe comte

#include <stdio.h>

float p, s=4, d=1;
int main(void) {
  for (; 4/d > 1E-5; d += 2)
        p -= (s = -s) / d;
  printf("%g\n", p);
}

version compactée

#include<stdio.h>
float
p,s=4,d=1;int
main(void){for(;4/d>1E-5;d+=2)p-=(s=-s)/d;printf("%g\n",p);}
2
répondu pmg 2009-01-03 17:57:06

langue: dc, nombre de caractères: 35

dc -e '9k0 1[d4r/r2+sar-lad274899>b]dsbxrp'
2
répondu Hynek -Pichi- Vychodil 2009-01-04 14:30:34

Ruby:

irb(main):031:0> 4*(1..10000).inject {|s,x| s+(-1)**(x+1)*1.0/(2*x-1)}
=> 3.14149265359003
1
répondu derobert 2009-01-02 18:13:55

64 chars en AWK:

~# awk 'BEGIN {p=1;for(i=3;i<10^6;i+=4){p=p-1/i+1/(i+2)}print p*4}'
3.14159
1
répondu LoranceStinson 2009-01-03 14:02:16

C# triche - 50 chars :

static single Pi(){
  return Math.Round(Math.PI, 5));
}

il dit seulement " en tenant compte de la formule écrire une fonction..."cela ne veut pas dire reproduire la formule de base du programme :) Pensez à l'extérieur de la boîte...

C# LINQ-78 chars :

static double pi = 4 * Enumerable.Range(0, 1000000)
               .Sum(n => Math.Pow(-1, n) / (2 * n + 1));

C# Suppléant LINQ - 94 caractères :

static double pi = return 4 * (from n in Enumerable.Range(0, 1000000)
                               select Math.Pow(-1, n) / (2 * n + 1)).Sum();

et enfin-cela prend le précédemment mentionné algorithme et condense mathématiquement de sorte que vous n'avez pas à vous soucier de changer les signes.

C# longhand-89 chars (sans compter les espaces non acquis) :

static double pi()
{
  var t = 0D;
  for (int n = 0; n < 1e6; t += Math.Pow(-1, n) / (2 * n + 1), n++) ;
  return 4 * t;
}
1
répondu BenAlabaster 2009-01-04 06:02:56
#!/usr/bin/env python
from math import *
denom = 1.0
imm = 0.0
sgn = 1
it = 0
for i in xrange(0, int(1e6)):
    imm += (sgn*1/denom)
    denom += 2
    sgn *= -1    
print str(4*imm)
1
répondu user48821 2009-01-05 10:35:56