# why 'lambda' and 'reduce'?

Bengt Richter bokr at oz.net
Sun Jun 15 01:08:12 CEST 2003

```On Sat, 14 Jun 2003 16:00:50 +0200, anton at vredegoor.doge.nl (Anton Vredegoor) wrote:

>bokr at oz.net (Bengt Richter) wrote:
>
>>I just thought to dig this up and turn it into a generator.
>>Something to check against ;-)
>
><snip pigen.py>
>
>Thanks for posting. After playing a while with it I noticed that the
>new itertools for Python23 are nice for this too. The version below
>doesn't use "n" and "k" in the generator and computes p and q in a
>for-loop. Also d and d1 are dropped for the sake of clarity, at the
>cost of computing just one extra a/b.
>
>Anton
>
>from sys import stdout
>from itertools import count,islice,imap
>
>def pq(x): return x*x,2*x+1
>
>def pigen():
>    a,b,c,d = 12,4,76,24
>    for p,q in imap(pq,count(3)):
>        while a/b == c/d:
>            yield str(a/b)
>            a,c = a%b*10, c%d*10
>        a,b,c,d = c,d,p*a+q*c,p*b+q*d
>
>def test():
>    ndigits = 60
>    map(stdout.write,islice(pigen(),ndigits))
>    print
>
>if __name__=='__main__':
>    test()

I guess I will have to install the 2.3 I downloaded ;-)

I am wondering if there could be some speed-enhancing short-cut
decisions in calculating a/b, given that the result is known to be
in range(10). (Perhaps it's already there as a byproduct of timbot wizardry).
also I wonder if divmod would be a good idea, since one would think
that would be cheaper than doing them separately.

Also, I wonder if calculating the digits to another base would make a difference,
e.g., base 2 (or maybe even 2**n to match internal representation of longs).
Base 2 would seem to allow division by comparison, and multiply py 2 as just
shift or add (again, maybe longs have some tweaks like that already built in?).

Other than the initial pi digit 3, IIRC just changing a,c = a%b*10, c%d*10
to a,c = a%b*2, c%d*2 is all you need to change the base. Then one could perhaps
reconsider the actual implementation of a few operations.

BTW, I noticed that you don't really need k at all since p is just successive squares
and q is a first difference of p that hence just advances by 2. E.g., you can
avoid a lot of multiplying:

--
p, q, a, b, a1, b1 = 1L, 3L, 4L, 1L, 12L, 4L
while True:
p+=q; q+=2L
a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1
while 1:
d,dr = divmod(a,b)
d1,d1r = divmod(a1,b1)
if d != d1: break
yield str(d)