Leibniz_Pi.py

Bengt Richter bokr at oz.net
Sat Oct 12 09:14:45 CEST 2002


On Fri, 11 Oct 2002 10:14:38 -0700, "Cousin Stanley" <CousinStanley at HotMail.com> wrote:

>Yesterday in the news group  comp.lang.java.help
>I found a Java example of the  Leibniz Pi  approximation
>and converted the Java code to Python ...=20
>
>The numerical results from either version=20
>using a  LARGE  number of terms as a program argument
>provide approximations for the number  Pi   that seems correct ...=20
>
>Using  1 million  terms as an input argument,
>the Java version is a bit faster, which I think
>is expected ...=20
>
>   On a 250 MHz Win98 machine ...=20
>  =20
>     Java SDK 1.4 .......  ~ 3-4   seconds
>    Python 2.2.1 .........  ~ 9-10 seconds
>
>Since I am fairly new to  BOTH  Java  AND  Python,
>I'm wondering if there are any ...=20
>
>  obvious oversights        ???
>  Python improvements ???
>
>Python code follows ...
>
>Cousin Stanley
>
>----------------------------------------------------------------
>
>'''=20
>    Leibniz_Pi.py
>
>    Pi =3D 4 * ( 1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 + 1/13 - 1/15 ... )
>
>    Using one million terms provides a good approximation ...
>
>    Posted to the NewsGroup
>    comp.lang.java.help           2002-10-10=20
>    By Jonas Lindstr=F6m
>
>    Converted to Python
>    By Stanley C. Kitching
>'''
>
>import sys
>print '\n    Approximate  Pi  via Leibniz Sequence '
>
>def calculate_pi( nTerms ) :
>
>    limit =3D ( 2 * nTerms ) - 1=20
>
>    if ( ( limit - 1 ) % 4 ) =3D=3D 0 : =20
>           sign =3D +1.0=20
>    else :=20
>           sign =3D -1.0
>
>    sum =3D 0.0
>
>    for i in range( limit , 0 , -2 ) :=20
>        sum +=3D  sign / i
>        sign =3D -sign
>
>    return 4.0 * sum=20
>
>nTerms =3D int( sys.argv[ 1 ] )=20
>
>Pi =3D calculate_pi( nTerms  )
>
>print '\n    Terms : ' , nTerms
>print '\n       Pi : ' , Pi
>
>

[ 0:01] C:\pywk\pi>pisigint.py
(Type Ctrl-C to stop generating pi)
   50  4085.12 dig/sec  31415926535897932384626433832795028841971693993751
  100  3292.99 dig/sec  05820974944592307816406286208998628034825342117067
  150  2422.61 dig/sec  98214808651328230664709384460955058223172535940812
  200  1851.27 dig/sec  84811174502841027019385211055596446229489549303819
  250  1473.79 dig/sec  64428810975665933446128475648233786783165271201909
  300  1277.74 dig/sec  14564856692346034861045432664821339360726024914127
  350  1087.28 dig/sec  37245870066063155881748815209209628292540917153643
  400  1003.15 dig/sec  67892590360011330530548820466521384146951941511609
  450   852.50 dig/sec  43305727036575959195309218611738193261179310511854
  500   742.55 dig/sec  80744623799627495673518857527248912279381830119491
  550   666.12 dig/sec  29833673362440656643086021394946395224737190702179
  600   624.75 dig/sec  86094370277053921717629317675238467481846766940513
  650   595.61 dig/sec  20005681271452635608277857713427577896091736371787
  700   535.77 dig/sec  21468440901224953430146549585371050792279689258923
  750   501.08 dig/sec  54201995611212902196086403441815981362977477130996
  800   470.28 dig/sec  05187072113499999983729780499510597317328160963185
  850   436.58 dig/sec  95024459455346908302642522308253344685035261931188
  900   333.36 dig/sec  17101000313783875288658753320838142061717766914730
  950   363.52 dig/sec  35982534904287554687311595628638823537875937519577
                        818577805321712
  965 Total digits

(965 total digits)

(I hit Ctrl-C fairly shortly).

You can redirect the pi digits, and watch the left part on a single line
being rewritten, which looks like so:

[ 0:10] C:\pywk\pi>python pisigint.py >zz.txt
(Type Ctrl-C to stop generating pi)
 2455 Total digits

[ 0:10] C:\pywk\pi>

----< pisigint.py >-------------------------
#!/usr/bin/python

# Print digits of pi forever, unless you hit Ctrl-C
# The output is split between stderr and stdout so that you can
# redirect the pi digits to a file, like so
#   python pisiginit.py > pidigits.txt
# and still see how many and how fast digits are being output. The latter
# info is rewritten without \n, so it does not scroll. If you don't
# redirect you see the latter to the left and the pi digits 50 at a time
# to the right. This is a modified version of the algorithm as found
# somewhere on the Ruby site.
#
# The algorithm, using Python's 'long' integers ("bignums"), works
# with continued fractions, and was conceived by Lambert Meertens.
#
# See also the ABC Programmer's Handbook, by Geurts, Meertens & Pemberton,
# published by Prentice-Hall (UK) Ltd., 1990.

import sys, signal
from time import clock
class SigHandler:
    def __init__(self):
        self.signaled = 0
    def __call__(self, sn, sf):
        self.signaled += 1

sh = SigHandler()
oldHandler = signal.signal(signal.SIGINT,sh)

k, a, b, a1, b1 = 2L, 4L, 1L, 12L, 4L

digits=0 # count to show progress
lines = 0
digline = []
start=clock()
sys.__stderr__.write('\r(Type Ctrl-C to stop generating pi)\n')

while not sh.signaled:
    # Next approximation
    p, q, k = k*k, 2*k+1, k+1
    a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1
    # Print common digits
    d = a / b
    d1 = a1 / b1
    while d == d1:
        digits += 1
        #sys.__stderr__.write('\r%5d' % (digits,))
        digline.append(d)
        if len(digline)==50:
            sys.__stderr__.write('\r%5d %8.2f dig/sec  ' % (digits, 50.0/(clock()-start)))
            lines += 1
            print ''.join(map(lambda x: chr(x+48),digline))
            digline = []
            start=clock()
        a, a1 = 10*(a%b), 10*(a1%b1)
        d, d1 = a/b, a1/b1
sys.__stderr__.write('\r'+' '*24)
if digline: print ''.join(map(lambda x: chr(x+48),digline))
sys.__stderr__.write('\r%5d Total digits                   \n'% (lines*50+len(digline)))
print '\n(%d total digits)' % (lines*50+len(digline))
signal.signal(signal.SIGINT,oldHandler)
--------------------------------------------

Regards,
Bengt Richter



More information about the Python-list mailing list