27

I have been thinking about this issue and I can't figure it out. Perhaps you can assist me. The problem is my code isn't working to output 1000 digits of pi in the Python coding language.

Here's my code:

def make_pi():
    q, r, t, k, m, x = 1, 0, 1, 1, 3, 3
    while True:
        if 4 * q + r - t < m * t:
            yield m
            q, r, t, k, m, x = (10*q, 10*(r-m*t), t, k, (10*(3*q+r))//t - 10*m, x)
        else:
            q, r, t, k, m, x = (q*k, (2*q+r)*x, t*x, k+1, (q*(7*k+2)+r*x)//(t*x), x+2)

digits = make_pi()
pi_list = []
my_array = []
for i in range(1000):
    my_array.append(str("hello, I'm an element in an array \n" ))
big_string = "".join(my_array)

print "here is a big string:\n %s" % big_string 

I know this code can be fixed to work, but I'm not sure what to fix... The print statement saying here is a big string and the my_array.append(str("hello, im an element in an array \n)) is just a filler for now. I know how all the code is used to work, but like I said before, I can't get it to shoot out that code.

Georgy
  • 12,464
  • 7
  • 65
  • 73
bobimo
  • 535
  • 2
  • 5
  • 10
  • 1
    that looks like a version of pi spigot algorithm, is it in fact? – Dan D. Jan 25 '12 at 15:02
  • 2
    Could you be a little clearer as to what the problem is; how does the behavior differ from what you expected? – Scott Hunter Jan 25 '12 at 15:05
  • 4
    The code looks suspiciously [like the code here](http://www.daniweb.com/software-development/python/code/216718) and [here](http://mail.python.org/pipermail/edu-sig/2006-July/006810.html). – Sven Marnach Jan 25 '12 at 15:07
  • This question seems really familiar. Was it asked here before and deleted? – Kris Harper Jan 25 '12 at 15:25
  • It is a version of the pi spigot algorithm XD. The output behavior doesn't work at all...what else is there to say. The question is similar because I asked it before then deleted it due to bad ratings, and the question was closed when in fact it was not answered.... – bobimo Jan 26 '12 at 13:46
  • 1
    related: [Gauss-Legendre Algorithm in python](http://stackoverflow.com/q/347734/4279) – jfs Nov 18 '13 at 08:14
  • change line `my_array.append(str("hello, I'm an element in an array \n" ))` to: `my_array.append(digits.next())` – Jerzyk Jun 09 '16 at 18:00

11 Answers11

38

If you don't want to implement your own algorithm, you can use mpmath.

try:
    # import version included with old SymPy
    from sympy.mpmath import mp
except ImportError:
    # import newer version
    from mpmath import mp

mp.dps = 1000  # set number of digits
print(mp.pi)   # print pi to a thousand places

Reference

Update: Code supports older and newer installations of SymPy (see comment).*

Garrett Hyde
  • 5,409
  • 8
  • 49
  • 55
  • 3
    When you install sympy in an environment like the ones created by anaconda, it will install `mpmath` separately and the import statement becomes `from mpmath import mp`. The code in this answer does not work anymore with modern versions of `sympy`. There is no `sympy.mpmath` anymore. – Zelphir Kaltstahl Nov 06 '16 at 17:11
26

Run this

def make_pi():
    q, r, t, k, m, x = 1, 0, 1, 1, 3, 3
    for j in range(1000):
        if 4 * q + r - t < m * t:
            yield m
            q, r, t, k, m, x = 10*q, 10*(r-m*t), t, k, (10*(3*q+r))//t - 10*m, x
        else:
            q, r, t, k, m, x = q*k, (2*q+r)*x, t*x, k+1, (q*(7*k+2)+r*x)//(t*x), x+2


my_array = []

for i in make_pi():
    my_array.append(str(i))

my_array = my_array[:1] + ['.'] + my_array[1:]
big_string = "".join(my_array)
print "here is a big string:\n %s" % big_string 

And read about yield operator from here: What does the "yield" keyword do?

Here is the answer:

3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337
temporary_user_name
  • 35,956
  • 47
  • 141
  • 220
batbaatar
  • 5,448
  • 2
  • 20
  • 26
  • 1
    I have a crazy idea to turn a Raspberry Pi loose on calculating pi out to many millions of places by letting it run 24/7 for years. The info presented in this question/answer seems very helpful. Thanks for posting this. I ran the code with a range of 50000 and it finished but I don't know if it is accurate. No errors were generated. Need to figure out how to deal with off loading partial results to disk rather than keeping it in memory. – WyomingGeezer Aug 23 '15 at 23:20
  • 3
    The "for j in range(1000)" makes it generate far fewer than 1000 digits. That should be changed back to "while True" or some other condition. – Don Hatch Apr 28 '16 at 03:59
  • 2
    I really do not like this code, fist - you change "make_pi" function with some limits without even trying to extract it to parameters, but even this is not needed - make_pi() return a generator and you can read from it using .next() as many times as you want, second why to call to make_pi twice? – Jerzyk Jun 09 '16 at 17:59
  • 1
    Any explanation, why this code is supposed to give PI, except for trying it? It is very unreadable. It reminds me of a transformation used for generating Fibonacci numbers in logarithmic time. – Zelphir Kaltstahl Nov 06 '16 at 15:10
  • why have you declared `pi_list` and assigned `digits` without using them? That's just confusing. – Arthur Dent Mar 14 '18 at 19:36
  • 1
    By doing j in range(4319), this answer will give 1000 digits – wazawoo Oct 21 '18 at 23:38
8

The accepted answer is incorrect, as noted in comments.

The OP's code appears to be based on an implementation of Spigot's algorithm copied from here.

To fix the code per the OP's question (although I renamed the variables and functions to match what they were in the original source), one solution might be:

#!/usr/bin/env python

DIGITS = 1000

def pi_digits(x):
    """Generate x digits of Pi."""
    q,r,t,k,n,l = 1,0,1,1,3,3
    while x >= 0:
        if 4*q+r-t < x*t:
            yield n
            x -= 1
            q,r,t,k,n,l = 10*q, 10*(r-n*t), t, k, (10*(3*q + r))/t-10*n, l
        else:
            q,r,t,k,n,l = q*k, (2*q+r)*l, t*l, k+1, (q*(7*k+2)+r*l)/(t*l), l+2

digits = [str(n) for n in list(pi_digits(DIGITS))]
print("%s.%s\n" % (digits.pop(0), "".join(digits)))

Also, here is a much faster* implementation, also apparently based on Spigot's algorithm:

#!/usr/bin/env python

DIGITS = 1000

def pi_digits(x):
    """Generate x digits of Pi."""
    k,a,b,a1,b1 = 2,4,1,12,4
    while x > 0:
        p,q,k = k * k, 2 * k + 1, k + 1
        a,b,a1,b1 = a1, b1, p*a + q*a1, p*b + q*b1
        d,d1 = a/b, a1/b1
        while d == d1 and x > 0:
            yield int(d)
            x -= 1
            a,a1 = 10*(a % b), 10*(a1 % b1)
            d,d1 = a/b, a1/b1

digits = [str(n) for n in list(pi_digits(DIGITS))]
print("%s.%s\n" % (digits.pop(0), "".join(digits)))

I tested both a few times against this online Pi digit generator.

All credit to this Gist by deeplook.

* Based on testing 10,000 digits, where I got about 7 seconds compared to about 1 second.

Alex Harvey
  • 14,494
  • 5
  • 61
  • 97
4

For up to 1 million digits of pi use math_pi (note: I am the author of the module)

Install with pip:

pip install math-pi

In Python:

>>> import math_pi
>>> print(math_pi.pi(b=1000))
3.1415926535...
math scat
  • 310
  • 8
  • 17
2

From Fabrice Bellard site: Pi Computation algorithm. Sorry for such a straightforward implementation. 1000 is fast enough (0.1s for me), but 10000 isn't such fast - 71s :-(

import time
from decimal import Decimal, getcontext

def compute(n):
    getcontext().prec = n
    res = Decimal(0)
    for i in range(n):
        a = Decimal(1)/(16**i)
        b = Decimal(4)/(8*i+1)
        c = Decimal(2)/(8*i+4)
        d = Decimal(1)/(8*i+5)
        e = Decimal(1)/(8*i+6)
        r = a*(b-c-d-e)
        res += r
    return res

if __name__ == "__main__":
    t1 = time.time()
    res = compute(1000)
    dt = time.time()-t1
    print(res)
    print(dt)
Guest007
  • 21
  • 4
2

I was solved with bellow formula 5-6 years ago.

Machin-like formula

Wikipedia: https://en.wikipedia.org/wiki/Machin-like_formula

Math formula

Sorry for the code quality. Variable names can be meaningless.

#-*- coding: utf-8 -*-

# Author:    Fatih Mert Doğancan
# Date:      02.12.2014

def arccot(x, u):
    sum = ussu = u // x
    n = 3
    sign = -1
    while 1:
        ussu = ussu // (x*x)
        term = ussu // n
        if not term:
            break
        sum += sign * term
        sign = -sign
        n += 2
    return sum

def pi(basamak):
    u = 10**(basamak+10)
    pi = 4 * (4*arccot(5,u) - arccot(239,u))
    return pi // 10**10

if __name__ == "__main__":
    print pi(1000) # 1000 
Fatih Mert Doğancan
  • 1,016
  • 14
  • 21
1

Here you can check whether your program outputs correct 1000 digits: http://spoj.com/CONSTANT

Of course you can use diff or tc as well but you'd have to copy these 1000 digits from somewhere and there you just submit your program and check whether the score is bigger than 999.

You can try to print even more digits there and thus get more points. Perhaps you'd enjoy it.

user1
  • 945
  • 2
  • 13
  • 37
1

I'm not familiar with your algorithm. Is it an implementation of BBP?

In any case, your make_pi is a generator. Try using it in a for loop:

for digit in make_pi():
    print digit

Note that this loop is infinite: make_pi() never throws StopIteration

Managu
  • 8,849
  • 2
  • 30
  • 36
0

Here is a different way I found here --> Python pi calculation? to approximate python based on the Chudnovsky brothers formula for generating Pi which I have sightly modified for my program.

def pifunction():
    numberofdigits = int(input("please enter the number of digits of pi that you want to generate"))
    getcontext().prec = numberofdigits

def calc(n):
    t = Decimal(0)
    pi = Decimal(0)
    deno = Decimal(0)
    k = 0
    for k in range(n):
        t = (Decimal(-1)**k)*(math.factorial(Decimal(6)*k))*(13591409+545140134*k)
        deno = math.factorial(3*k)*(math.factorial(k)**Decimal(3))*(640320**(3*k))
        pi += Decimal(t)/Decimal(deno)
    pi = pi * Decimal(12)/Decimal(640320**Decimal(1.5))
    pi = 1/pi
    return str(pi)
print(calc(1))

I hope this helps as you can generate any number of digits of pi that you wish to generate.

Community
  • 1
  • 1
Timothy
  • 11
  • If I remove the first "def pifunction():" so that it runs without syntax error, the answer is only accurate to about 13 places: 3.1415926535897342076 – Don Hatch Apr 28 '16 at 03:43
  • That is because of the parameter on the last line. Put in a 2 and it does much better, and so on. Function pifunction() is not used and would not directly affect the accuracy of the calculation, only the precision. On the other hand, this method converges very quickly and because terms alternate in sign, you get bounds on the true value. – 4dummies Oct 07 '18 at 20:13
0

wallis formula can get to 3.141592661439964 but a more efficient way is needed to solve this problem.

https://www.youtube.com/watch?v=EZSiQv_G9HM

and now my code

x, y, summing = 2, 3, 4

for count in range (0,100000000):
    summing *= (x/y)
    x += 2
    summing *= (x/y)
    y += 2

print (summing)
lenik
  • 23,228
  • 4
  • 34
  • 43
tanny
  • 1
0

Does this do what you want?

i = 0;
pi_str = ""
for x in make_pi():
    pi_str += str(x)
    i += 1
    if i == 1001:
        break

print "pi= %s.%s" % (pi_str[0],pi_str[1:])
Scott Hunter
  • 48,888
  • 12
  • 60
  • 101