<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:wfw="http://wellformedweb.org/CommentAPI/"
     >
  <channel>
    <title>Nick Craig-Wood's Articles</title>
    <link>http://www.craig-wood.com/nick/articles</link>
    <description>Nick Craig-Wood's Articles</description>
    <pubDate>Sat, 24 Dec 2011 22:52:02 GMT</pubDate>
    <generator>Blogofile</generator>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>How I Solved the GCHQ challenge</title>
      <link>http://www.craig-wood.com/nick/articles/how-i-solved-the-gchq-challenge</link>
      <pubDate>Sun, 04 Dec 2011 20:00:00 GMT</pubDate>
      <category><![CDATA[maths]]></category>
      <category><![CDATA[python]]></category>
      <guid>http://www.craig-wood.com/nick/articles/how-i-solved-the-gchq-challenge</guid>
      <description>How I Solved the GCHQ challenge</description>
      <content:encoded><![CDATA[<div class="document">
<p>This is an unsanitised account of how I solved the GCHQ challenge at
<a class="reference external" href="http://www.canyoucrackit.co.uk/">http://www.canyoucrackit.co.uk/</a>.  <a class="reference external" href="http://www.bbc.co.uk/news/technology-15968878">According to the BBC</a> the
competition began in secret on the 3rd of November 2011 and will
continue until the 12th of December.  I was going to hold back this
publication until the contest ended but <a class="reference external" href="http://news.slashdot.org/story/11/12/04/1725253/gchq-challenge-solution-explained">a solution</a> has just made it
to the front page of slashdot so I think the jig is up!</p>
<p>This writeup includes the wrong turnings I took and the bad
assumptions I made along the way so any reader can see the kind of
thought processes necessary.  I very deliberately did no searching on
the Internet about the puzzle so all the work below (and the mistakes)
are mine alone!</p>
<p>The programs linked to in the article are the final versions, I didn't
keep the intermediate versions which I talk about in the text, so
you'll have to imagine what they looked like.</p>
<div class="warning">
<p class="first admonition-title">Warning</p>
<p class="last">This article contains spoilers on how to do the challenge - don't read any further if you want to solve it yourself!</p>
</div>
<div class="section" id="stage-1">
<h1>Stage 1</h1>
<p>The challenge opens showing a single image with a load of hex digits
in and a form to submit your answer.  The image looks like this:</p>
<img alt="GCHQ cyber challenge" src="/nick/pub/gchq-challenge/cyber.png" />
<p>The first thing I did was to decode the hex data.  Using a python
program of course!  I played around with trying to get it to display
an image.  It is obviously low entropy but what is it?  Not an image
anyway.</p>
<p>I used <a class="reference external" href="/nick/pub/gchq-challenge/cyber.py">cyber.py</a> to save it to a binary file and ran the unix &quot;file&quot;
utility on it which told me it was x86 code:</p>
<pre class="literal-block">
$ file cyber.bin
cyber.bin: DOS executable (COM)
</pre>
<p>Interesting. A disassembly was required <a class="reference external" href="/nick/pub/gchq-challenge/cyber.disassembly.asm">cyber.disassembly.asm</a>:</p>
<pre class="literal-block">
x86dis -r 0 160  -s intel &lt; cyber.bin &gt; cyber.disassembly.asm
</pre>
<p>The code appeared to be linux flavour, exiting politely with the
correct <tt class="docutils literal">int 0x80</tt> call.</p>
<p>The obvious next step is to run the code.  It is bare code which you
can't just run on any modern OS.  I could have added headers to it but
I decided to write <a class="reference external" href="/nick/pub/gchq-challenge/cyber.c">cyber.c</a> to load it into memory instead.  I used
<tt class="docutils literal">mmap</tt> to map a padded version of the code so I could get the code
and the stack under my control and examine it after the code had
exited:</p>
<pre class="literal-block">
gcc -g -m32 -Wall -static -o cyber cyber.c
</pre>
<p>Running the code, it seemed to be early terminating - needing
0x42424242 or &quot;BBBB&quot; on the end to continue according to this bit of
code:</p>
<pre class="literal-block">
0000004A 58                                 pop     eax
0000004B 3D 42 42 42 42                     cmp     eax, 0x42424242
00000050 75 3B                              jnz     0x0000008D ; exit
</pre>
<p>I tried padding with &quot;BBBB&quot; and it core dumped this time.  After
studying the disassembly some more and experimenting I noted that it
needed &quot;BBBB&quot; <strong>and</strong> a 4 byte length.  Running that it appears to
decrypt something on the stack this time, so I'm getting somewhere.</p>
<p>But what to decrypt?  I needed a string starting with &quot;BBBB&quot;.  I
recursively downloaded the entire website and grepped it for &quot;BBBB&quot;
without success.  However on really close examination of a hex dump of
cyber.png I discovered this:</p>
<pre class="literal-block">
00000050: 1233 7e39 c170 0000 005d 6954 5874 436f  .3~9.p...]iTXtCo
00000060: 6d6d 656e 7400 0000 0000 516b 4a43 516a  mment.....QkJCQj
00000070: 4941 4141 4352 3250 4674 6343 4136 7132  IAAACR2PFtcCA6q2
00000080: 6561 4338 5352 2b38 646d 442f 7a4e 7a4c  eaC8SR+8dmD/zNzL
00000090: 5143 2b74 6433 7446 5134 7178 384f 3434  QC+td3tFQ4qx8O44
000000a0: 3754 4465 755a 7735 502b 3053 7362 4563  7TDeuZw5P+0SsbEc
000000b0: 5952 0a37 386a 4b4c 773d 3d32 cabe f100  YR.78jKLw==2....
</pre>
<p>That string &quot;QkJCQj...78jKLw==&quot; with upper and lower case letters, '+'
and '/' and the trailing '==' screams <a class="reference external" href="http://en.wikipedia.org/wiki/Base64">base64 encoding</a> to me.  I
decoded it in python and it decodes to <tt class="docutils literal">BBBB2\x00\x00\x00\x91</tt>... -
hooray a string starting with &quot;BBBB&quot; and a sensible looking length!  I
then modified <a class="reference external" href="/nick/pub/gchq-challenge/cyber.py">cyber.py</a> to add that on the end of the code and ran
the <a class="reference external" href="/nick/pub/gchq-challenge/cyber.c">cyber.c</a> binary.  After it had ran I examined the stack in the
<tt class="docutils literal">cyber.bin.padded</tt> file originally written by <tt class="docutils literal">cyber.py</tt>.  I saw
this:</p>
<pre class="literal-block">
00002c0: 00 00 00 00 00 00 00 00 00 00 47 45 54 20 2f 31  ..........GET /1
00002d0: 35 62 34 33 36 64 65 31 66 39 31 30 37 66 33 37  5b436de1f9107f37
00002e0: 37 38 61 61 64 35 32 35 65 35 64 30 62 32 30 2e  78aad525e5d0b20.
00002f0: 6a 73 20 48 54 54 50 2f de e6 fb 2f ef ae 5d aa  js HTTP/.../..].
</pre>
<p>Which looks very like an HTTP transaction, ie a coded instruction to
fetch a file, so I did:</p>
<pre class="literal-block">
$ wget http://www.canyoucrackit.co.uk/15b436de1f9107f3778aad525e5d0b20.js
</pre>
</div>
<div class="section" id="stage-2">
<h1>Stage 2</h1>
<p>The downloaded file <a class="reference external" href="/nick/pub/gchq-challenge/15b436de1f9107f3778aad525e5d0b20.js">15b436de1f9107f3778aad525e5d0b20.js</a> is a
description of a VM with an initial state, but no code to implement
the VM.  It has a very realistic and amusing initial commment!  It
also says &quot;stage 2 of 3&quot; which is the first indication how long this
challenge is going to be.</p>
<p>Otherwise it seems a reasonably straightforward job to implement the
VM and I got cracking on <a class="reference external" href="/nick/pub/gchq-challenge/vm.py">vm.py</a> after reading that.  Note that it
has 8 bytes of 'firmware' which don't seem to fit in anywhere which is
a bit puzzling.</p>
<p>Wasted a lot of time trying to get the VM to work.  Tried poking the
firmware in various imaginitive places.  Found a few bugs then finally
re-read the doc again - Ah-ha it is 16 byte segment size, not a 16 bit
register... Duh!</p>
<p>Fixed that and it runs much better now actually decrypting stuff and
halts properly.</p>
<p>Found this in the memory in <tt class="docutils literal">final.core</tt> after <a class="reference external" href="/nick/pub/gchq-challenge/vm.py">vm.py</a> had run:</p>
<pre class="literal-block">
00001c0: 47 45 54 20 2f 64 61 37 35 33 37 30 66 65 31 35  GET /da75370fe15
00001d0: 63 34 31 34 38 62 64 34 63 65 65 63 38 36 31 66  c4148bd4ceec861f
00001e0: 62 64 61 61 35 2e 65 78 65 20 48 54 54 50 2f 31  bdaa5.exe HTTP/1
00001f0: 2e 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00  .0..............
</pre>
<p>That seems like an instruction to fetch something from the web site again:</p>
<pre class="literal-block">
$ wget http://www.canyoucrackit.co.uk/da75370fe15c4148bd4ceec861fbdaa5.exe
</pre>
<p>Haven't used the firmware - wonder where that fits in...</p>
</div>
<div class="section" id="stage-3">
<h1>Stage 3</h1>
<p>I looked in <a class="reference external" href="/nick/pub/gchq-challenge/da75370fe15c4148bd4ceec861fbdaa5.exe">da75370fe15c4148bd4ceec861fbdaa5.exe</a> - and found it to
be a windows x86 executable.  It seems to be using the cygcrypt dll
from cygwin and the <tt class="docutils literal">crypt()</tt> function.  It has a string in it which
looks exactly like a DES password crypt &quot;hqDTK7b8K2rvw&quot;.  I then set
<a class="reference external" href="http://www.openwall.com/john/">John the Ripper</a> and <a class="reference external" href="http://packages.debian.org/squeeze/crack">crack</a> off on it for good measure to find
the encrypted password.</p>
<p>John the Ripper found the password <tt class="docutils literal">cyberwin</tt> in 2 hours. The easy
one was my test to make sure it was working:</p>
<pre class="literal-block">
Loaded 2 password hashes with 2 different salts (Traditional DES [128/128 BS SSE2-16])
easy             (trivial)
cyberwin         (test)
guesses: 2  time: 0:02:01:42 (3)  c/s: 1537K  trying: cufqnm5! - cyberwen
Use the &quot;--show&quot; option to display all of the cracked passwords reliably
</pre>
<p>And double checking with python:</p>
<pre class="literal-block">
&gt;&gt;&gt; crypt(&quot;cyberwin&quot;, &quot;hq&quot;) == &quot;hqDTK7b8K2rvw&quot;
True
</pre>
<p>Meanwhile I tried running the exe on windows but it doesn't run
without that dll.</p>
<p>After installing cygwin with the &quot;crypt&quot; package which has the correct
dll in, I copied <tt class="docutils literal"><span class="pre">cygcrypt-0.dll</span></tt> and <tt class="docutils literal">cygwin1.dll</tt> into my
working directory.  The exe now runs and gives:</p>
<pre class="literal-block">
&gt;da75370fe15c4148bd4ceec861fbdaa5.exe

keygen.exe

usage: keygen.exe hostname

&gt;da75370fe15c4148bd4ceec861fbdaa5.exe localhost

keygen.exe

error: license.txt not found
</pre>
<p>I then tried it with &quot;cyberwin&quot; in license.txt:</p>
<pre class="literal-block">
&gt;da75370fe15c4148bd4ceec861fbdaa5.exe localhost

keygen.exe

error: license.txt invalid
</pre>
<p>Hmm, I was expecting that to work.</p>
<p>Looking through the <a class="reference external" href="/pub/gchq-challenge/keygen.edit.asm">keygen.edit.asm</a> (my annotated version) I
discovered that the password should be prefixed with &quot;gchq&quot;.  The
first hint as to who set this puzzle!</p>
<pre class="literal-block">
cmp    [ebp+var_38], 71686367h ; gchq
jnz    short invalid_license
</pre>
<p>Putting &quot;gchqcyberwin&quot; into the <tt class="docutils literal">license.txt</tt> and running the
program goes better this time.  It fetches a page this time, but it is
a 404 not found.  Note that this isn't the normal 404 page because the
exe uses HTTP/1.0 rather than HTTP/1.1:</p>
<pre class="literal-block">
&gt;da75370fe15c4148bd4ceec861fbdaa5.exe www.canyoucrackit.co.uk

keygen.exe

loading stage1 license key(s)...
loading stage2 license key(s)...

request:

GET /hqDTK7b8K2rvw/0/0/0/key.txt HTTP/1.0

response:

HTTP/1.1 404 Not Found
Content-Type: text/html; charset=us-ascii
Server: Microsoft-HTTPAPI/2.0
Date: Sat, 03 Dec 2011 09:29:29 GMT
Connection: close
Content-Length: 315

&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot;&quot;http://www.w3.org/TR/html4/strict.dtd&quot;&gt;
&lt;HTML&gt;&lt;HEAD&gt;&lt;TITLE&gt;Not Found&lt;/TITLE&gt;
&lt;META HTTP-EQUIV=&quot;Content-Type&quot; Content=&quot;text/html; charset=us-ascii&quot;&gt;&lt;/HEAD&gt;
&lt;BODY&gt;&lt;h2&gt;Not Found&lt;/h2&gt;
&lt;hr&gt;&lt;p&gt;HTTP Error 404. The requested resource is not found.&lt;/p&gt;
&lt;/BODY&gt;&lt;/HTML&gt;
</pre>
<p>Trying the above in the web browser gives the normal 404 message.
Trying with telnet see that it needs HTTP/1.0. HTTP/1.1 with host
header gives normal page.  Trying &quot;GET / HTTP/1.0&quot; gives the same
message so probably a red herring to do with the server (or not see
later!).</p>
<p>The fact that the page isn't found means that there is something
missing.  But what? The code is executing the equivalent of this to
make the GET string to fetch the page:</p>
<pre class="literal-block">
sprintf(buffer, &quot;GET /%s/%x/%x/%x/key.txt HTTP/1.0\r\n\r\n&quot;, crypted_string, key1, key2, key2);
</pre>
<p>However key1, key2 and key3 are all 0 which doesn't look right. I
tried some things for those missing %x parameters:</p>
<pre class="literal-block">
&gt;&gt;&gt; t = &quot;gchqcyberwin&quot;
&gt;&gt;&gt; from struct import *
&gt;&gt;&gt; [ &quot;%x&quot; %x  for x in unpack(&quot;&gt;iii&quot;, t) ]
['67636871', '63796265', '7277696e']
&gt;&gt;&gt; [ &quot;%x&quot; %x  for x in unpack(&quot;&lt;iii&quot;, t) ]
['71686367', '65627963', '6e697772']
</pre>
<p>Try:</p>
<pre class="literal-block">
wget http://www.canyoucrackit.co.uk/hqDTK7b8K2rvw/71686367/65627963/6e697772/key.txt
wget http://www.canyoucrackit.co.uk/hqDTK7b8K2rvw/67636871/63796265/7277696e/key.txt
</pre>
<p>But no luck.</p>
<p>More study of the <a class="reference external" href="/pub/gchq-challenge/keygen.edit.asm">keygen.edit.asm</a> disassembly reveals that key1,
key2, key3 come from the end of the <tt class="docutils literal">license.txt</tt> file after
&quot;gchqcyberwin&quot;.  So that makes 24 bytes of secrets read from the
licence file which is the size of the buffer the code allocates.</p>
<p>Ah-Ha! The clue is in the &quot;loading stageX license key(s)...&quot; messages.</p>
<p>This bit of assembler code gives it away (annotations by me):</p>
<pre class="literal-block">
loc_4011A5:             ; &quot;loading stage1 license key(s)...\n&quot;
mov     [esp+78h+var_78], offset aLoadingStage1L
call    printf
mov     eax, [ebp+var_2C]       ; copy 4 bytes of the licence file
mov     [ebp+var_48], eax
mov     [esp+78h+var_78], offset aLoadingStage2L ; &quot;loading stage2 license key(s)...\n\n&quot;
call    printf
mov     eax, [ebp+var_28]       ; ...and another 4 bytes
mov     [ebp+var_44], eax
mov     eax, [ebp+var_24]       ; ..and another 4 bytes
mov     [ebp+var_40], eax
</pre>
<p>It prints &quot;loading stage1 license keys(s)...&quot; loads 4 bytes, then
&quot;loading stage2 license key(s)...&quot; and loads 8 bytes.  Stage 1 is the
first stage of the puzzle - need 4 bytes from this - how about the
unused 4 bytes at the start of the code that is jumped over &quot;af c2 bf
a3&quot;.  Stage2 is the second stage from which we need 8 bytes - the
mysteriously unused firmware seems appropriate.</p>
<p>I wrote <a class="reference external" href="/nick/pub/gchq-challenge/keyfetch.py">keyfetch.py</a> to fiddle with the endianess and after a bit of
trial and error it worked:</p>
<pre class="literal-block">
GET 'http://www.canyoucrackit.co.uk/hqDTK7b8K2rvw/a3bfc2af/d2ab1f05/da13f110/key.txt'
Pr0t3ct!on
</pre>
<p>Fetched using <tt class="docutils literal">HTTP/1.1</tt> and the <tt class="docutils literal">GET</tt> program.  Which looks like
it could be the password! But it doesn't work :-(</p>
<p>The headers showed nothing interesting.  I then tried using
<tt class="docutils literal">keygen.exe</tt> with a corrected license file - it didn't work as I
expected as the webserver doesn't support HTTP/1.0 (or maybe I did
something wrong).</p>
<p>However trying it by hand using telnet and <tt class="docutils literal">HTTP/1.0</tt> does do
something different:</p>
<pre class="literal-block">
$ telnet www.canyoucrackit.co.uk 80
Trying 31.222.164.161...
Connected to www.canyoucrackit.co.uk.
Escape character is '^]'.
GET http://www.canyoucrackit.co.uk/hqDTK7b8K2rvw/a3bfc2af/d2ab1f05/da13f110/key.txt HTTP/1.0

HTTP/1.1 200 OK
Content-Type: text/plain
Last-Modified: Wed, 26 Oct 2011 08:40:14 GMT
Accept-Ranges: bytes
ETag: &quot;bc46bae1ba93cc1:0&quot;
Server: Microsoft-IIS/7.5
Date: Sun, 04 Dec 2011 11:14:54 GMT
Connection: close
Content-Length: 37

Pr0t3ct!on#cyber_security&#64;12*12.2011+Connection closed by foreign host.
$
</pre>
<p>I reworked <a class="reference external" href="/nick/pub/gchq-challenge/keyfetch.py">keyfetch.py</a> to make the fetch using <tt class="docutils literal">HTTP/1.0</tt> to double check.</p>
<p>Trying <tt class="docutils literal">Pr0t3ct!on#cyber_security&#64;12*12.2011+</tt> as the key does
indeed work and produces this page: <a class="reference external" href="http://www.canyoucrackit.co.uk/soyoudidit.asp">http://www.canyoucrackit.co.uk/soyoudidit.asp</a>:</p>
<blockquote>
So you did it. Well done! Now this is where it gets
interesting. Could you use your skills and ingenuity to combat
terrorism and cyber threats? As one of our experts, you'll help
protect our nation's security and the lives of thousands. Every
day will bring new challenges, new solutions to find – and new
ways to prove that you're one of the best.</blockquote>
<p>I'm not going to apply for a job as I'm rather fully employed elsewhere, but it was a fun challenge!</p>
</div>
<div class="section" id="postmortem">
<h1>Postmortem</h1>
<p>I didn't see this until the 1st December 2011 when a colleague at work
(thanks Tom!)  mentioned it to me and I didn't have time to work on it
until Friday the 2nd of December.  It took me one very late night on
Friday and intermittent hacking on Saturday and Sunday to complete the
challenge - about 12 hours in total.  I spent 3 hours tracking down
that mis-understanding in <a class="reference external" href="/nick/pub/gchq-challenge/vm.py">vm.py</a> about 16 byte segments and 2 hours
trying to work out what the missing 12 bytes were in the URL in stage
3.</p>
<p>I think Stage 1 was very hard - perhaps deliberately so.  Stage 2 was
much easier - there was a defined goal and any competent computer
scientist would be able to knock up the VM code.  Stage 3 involved an
awful lot of reading C compiler created x86 assembler which was
painful.  I suspect I could have done it a lot quicker if I'd had some
better tools.  An interactive disassembling debugger would have been
useful - I used to have such a thing when I did 68000 programming and
it was a wonder.</p>
<p>I note that I didn't actually have to crack the encrypted password in
Stage 3.  I could have just changed one byte and have it ignore the
check but I was expecting that the code would actually need to use it.
Alas no and so much for <a class="reference external" href="http://www.openwall.com/john/">John the Ripper</a>!</p>
<p>Finally thanks to GCHQ for making the challenge - it was a good one!</p>
</div>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Pi - Chudnovsky</title>
      <link>http://www.craig-wood.com/nick/articles/pi-chudnovsky</link>
      <pubDate>Sat, 08 Oct 2011 00:00:00 BST</pubDate>
      <category><![CDATA[maths]]></category>
      <category><![CDATA[pymath]]></category>
      <category><![CDATA[python]]></category>
      <guid>http://www.craig-wood.com/nick/articles/pi-chudnovsky</guid>
      <description>Pi - Chudnovsky</description>
      <content:encoded><![CDATA[<div class="document">
<p>In <a class="reference external" href="/nick/articles/pi-machin/">Part 3</a> we managed to calculate 1,000,000 decimal places of π with <a class="reference external" href="http://en.wikipedia.org/wiki/John_Machin">Machin</a>'s <tt class="docutils literal">arctan</tt> formula.  Our stated aim was 100,000,000 places which we are going to achieve now!</p>
<div class="sidebar">
<p class="first sidebar-title">Fun with Maths and Python</p>
<p class="last">This is a having fun with maths and python article.  See <a class="reference external" href="/nick/articles/fun-with-maths-and-python-introduction/">the introduction</a> for important information!</p>
</div>
<p>We have still got a long way to go though, and we'll have to improve both our algorithm (formula) for π and our implementation.</p>
<p>The current darling of the π world is the <a class="reference external" href="http://en.wikipedia.org/wiki/Chudnovsky_algorithm">Chudnovsky algorithm</a> which is similar to the <tt class="docutils literal">arctan</tt> formula but it converges much quicker.  It is also rather complicated.  The formula itself is derived from one by <a class="reference external" href="http://www-history.mcs.st-and.ac.uk/Biographies/Ramanujan.html">Ramanjuan</a> who's work was extraordinary in the extreme.  It isn't trivial to prove, so I won't!  Here is Chudnovsky's formula for π as it is usually stated:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/13e67da9779a237b0d3b4b0fa5d70d12.png" alt="\[
\frac{1}{\pi} = 12 \sum^\infty_{k=0} \frac{(-1)^k (6k)! (13591409 + 545140134k)}{(3k)!(k!)^3 640320^{3k + 3/2}}
\]
" title="\[
\frac{1}{\pi} = 12 \sum^\infty_{k=0} \frac{(-1)^k (6k)! (13591409 + 545140134k)}{(3k)!(k!)^3 640320^{3k + 3/2}}
\]
" /></div>
<p>That is quite a complicated formula, we will make more comprehensible in a moment.  If you haven't seen the Σ notation before it just like a <tt class="docutils literal">sum</tt> over a <tt class="docutils literal">for</tt> loop in python.  For example:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/b63b93c8cb0658657d92a47f208b2a99.png" alt="\[
\sum^{10}_{k=1} k^2
\]
" title="\[
\sum^{10}_{k=1} k^2
\]
" /></div>
<p>Is exactly the same as this python fragment:</p>
<div class="literal-block">

<div class="pygments_murphy"><pre><span class="nb">sum</span><span class="p">(</span><span class="n">k</span><span class="o">**</span><span class="mi">2</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">11</span><span class="p">))</span>
</pre></div>


</div>
<p>First let's get rid of that funny fractional power:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/40f2e34873e611fb04c7b93ed846b724.png" alt="\begin{eqnarray*}
\frac{1}{\pi} &amp;=&amp; 12 \sum^\infty_{k=0} \frac{(-1)^k (6k)! (13591409 + 545140134k)}{(3k)!(k!)^3 640320^{3k + 3/2}} \\
              &amp;=&amp; \frac{12}{640320 \sqrt{640320}} \sum^\infty_{k=0} \frac{(-1)^k (6k)! (13591409 + 545140134k)}{(3k)!(k!)^3 640320^{3k}} \\
              &amp;=&amp; \frac{1}{426880 \sqrt{10005}} \sum^\infty_{k=0} \frac{(-1)^k (6k)! (13591409 + 545140134k)}{(3k)!(k!)^3 640320^{3k}} \\
\end{eqnarray*}
" title="\begin{eqnarray*}
\frac{1}{\pi} &amp;=&amp; 12 \sum^\infty_{k=0} \frac{(-1)^k (6k)! (13591409 + 545140134k)}{(3k)!(k!)^3 640320^{3k + 3/2}} \\
              &amp;=&amp; \frac{12}{640320 \sqrt{640320}} \sum^\infty_{k=0} \frac{(-1)^k (6k)! (13591409 + 545140134k)}{(3k)!(k!)^3 640320^{3k}} \\
              &amp;=&amp; \frac{1}{426880 \sqrt{10005}} \sum^\infty_{k=0} \frac{(-1)^k (6k)! (13591409 + 545140134k)}{(3k)!(k!)^3 640320^{3k}} \\
\end{eqnarray*}
" /></div>
<p>Now let's split it into two independent parts.  See how there is a <tt class="docutils literal">+</tt> sign inside the Σ?  We can split it into two series which we will call <tt class="docutils literal">a</tt> and <tt class="docutils literal">b</tt> and work out what π is in terms of <tt class="docutils literal">a</tt> and <tt class="docutils literal">b</tt>:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/08a500687c950febe17c567b76974442.png" alt="\begin{eqnarray*}
a     &amp;=&amp; \sum^\infty_{k=0} \frac{(-1)^k (6k)!}{(3k)!(k!)^3 640320^{3k}} \\
      &amp;=&amp; 1
          - \frac{6\cdot5\cdot4}{(1)^3 640320^3}
          + \frac{12\cdot11\cdot10\cdot9\cdot8\cdot7}{(2\cdot1)^3 640320^6}
          - \frac{18\cdot17\cdots13}{(3\cdot2\cdot1)^3 640320^{9}}
          + \cdots \\
b     &amp;=&amp; \sum^\infty_{k=0} \frac{(-1)^k (6k)!k}{(3k)!(k!)^3 640320^{3k}} \\
\frac{1}{\pi} &amp;=&amp; \frac{13591409a + 545140134b}{426880 \sqrt{10005}} \\
\pi           &amp;=&amp; \frac{426880 \sqrt{10005}}{13591409a + 545140134b} \\
\end{eqnarray*}
" title="\begin{eqnarray*}
a     &amp;=&amp; \sum^\infty_{k=0} \frac{(-1)^k (6k)!}{(3k)!(k!)^3 640320^{3k}} \\
      &amp;=&amp; 1
          - \frac{6\cdot5\cdot4}{(1)^3 640320^3}
          + \frac{12\cdot11\cdot10\cdot9\cdot8\cdot7}{(2\cdot1)^3 640320^6}
          - \frac{18\cdot17\cdots13}{(3\cdot2\cdot1)^3 640320^{9}}
          + \cdots \\
b     &amp;=&amp; \sum^\infty_{k=0} \frac{(-1)^k (6k)!k}{(3k)!(k!)^3 640320^{3k}} \\
\frac{1}{\pi} &amp;=&amp; \frac{13591409a + 545140134b}{426880 \sqrt{10005}} \\
\pi           &amp;=&amp; \frac{426880 \sqrt{10005}}{13591409a + 545140134b} \\
\end{eqnarray*}
" /></div>
<p>Finally note that we can calculate the next <tt class="docutils literal">a</tt> term from the
previous one, and the <tt class="docutils literal">b</tt> terms from the <tt class="docutils literal">a</tt> terms which
simplifies the calculations rather a lot.</p>
<div class="literal-block"><img class="math" src="/nick/images/math/03abb62652ffd044dd7c34d7bc04fd83.png" alt="\begin{eqnarray*}
a_k &amp;=&amp; \frac{(-1)^k (6k)!}{(3k)!(k!)^3 640320^{3k}} \\
b_k &amp;=&amp; k \cdot a_k \\
\frac{a_{k}}{a_{k-1}} &amp;=&amp; - \frac{(6k-5)(6k-4)(6k-3)(6k-2)(6k-1)6k}{3k(3k-1)(3k-2)k^3 640320^3} \\
                      &amp;=&amp; - \frac{24(6k-5)(2k-1)(6k-1)}{k^3 640320^3} \\
\end{eqnarray*}
" title="\begin{eqnarray*}
a_k &amp;=&amp; \frac{(-1)^k (6k)!}{(3k)!(k!)^3 640320^{3k}} \\
b_k &amp;=&amp; k \cdot a_k \\
\frac{a_{k}}{a_{k-1}} &amp;=&amp; - \frac{(6k-5)(6k-4)(6k-3)(6k-2)(6k-1)6k}{3k(3k-1)(3k-2)k^3 640320^3} \\
                      &amp;=&amp; - \frac{24(6k-5)(2k-1)(6k-1)}{k^3 640320^3} \\
\end{eqnarray*}
" /></div>
<p>OK that was a lot of maths!  But it is now in an easy to compute state, which we can do like this:</p>
<div class="literal-block">

<div class="pygments_murphy"><pre><span class="k">def</span> <span class="nf">pi_chudnovsky</span><span class="p">(</span><span class="n">one</span><span class="o">=</span><span class="mi">1000000</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Calculate pi using Chudnovsky&#39;s series</span>

<span class="sd">    This calculates it in fixed point, using the value for one passed in</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">k</span> <span class="o">=</span> <span class="mi">1</span>
    <span class="n">a_k</span> <span class="o">=</span> <span class="n">one</span>
    <span class="n">a_sum</span> <span class="o">=</span> <span class="n">one</span>
    <span class="n">b_sum</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="n">C</span> <span class="o">=</span> <span class="mi">640320</span>
    <span class="n">C3_OVER_24</span> <span class="o">=</span> <span class="n">C</span><span class="o">**</span><span class="mi">3</span> <span class="o">//</span> <span class="mi">24</span>
    <span class="k">while</span> <span class="mi">1</span><span class="p">:</span>
        <span class="n">a_k</span> <span class="o">*=</span> <span class="o">-</span><span class="p">(</span><span class="mi">6</span><span class="o">*</span><span class="n">k</span><span class="o">-</span><span class="mi">5</span><span class="p">)</span><span class="o">*</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">k</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="p">(</span><span class="mi">6</span><span class="o">*</span><span class="n">k</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
        <span class="n">a_k</span> <span class="o">//=</span> <span class="n">k</span><span class="o">*</span><span class="n">k</span><span class="o">*</span><span class="n">k</span><span class="o">*</span><span class="n">C3_OVER_24</span>
        <span class="n">a_sum</span> <span class="o">+=</span> <span class="n">a_k</span>
        <span class="n">b_sum</span> <span class="o">+=</span> <span class="n">k</span> <span class="o">*</span> <span class="n">a_k</span>
        <span class="n">k</span> <span class="o">+=</span> <span class="mi">1</span>
        <span class="k">if</span> <span class="n">a_k</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">break</span>
    <span class="n">total</span> <span class="o">=</span> <span class="mi">13591409</span><span class="o">*</span><span class="n">a_sum</span> <span class="o">+</span> <span class="mi">545140134</span><span class="o">*</span><span class="n">b_sum</span>
    <span class="n">pi</span> <span class="o">=</span> <span class="p">(</span><span class="mi">426880</span><span class="o">*</span><span class="n">sqrt</span><span class="p">(</span><span class="mi">10005</span><span class="o">*</span><span class="n">one</span><span class="p">,</span> <span class="n">one</span><span class="p">)</span><span class="o">*</span><span class="n">one</span><span class="p">)</span> <span class="o">//</span> <span class="n">total</span>
    <span class="k">return</span> <span class="n">pi</span>
</pre></div>


</div>
<p>We need to be able to take the square root of long integers which
python doesn't have a built in for.  Luckily this is easy to provide.
This uses a <a class="reference external" href="http://en.wikipedia.org/wiki/Newton's_method#Square_root_of_a_number">square root algorithm devised by Newton</a> which doubles
the number of significant places in the answer (quadratic convergence)
each iteration:</p>
<div class="literal-block">

<div class="pygments_murphy"><pre> <span class="k">def</span> <span class="nf">sqrt</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">one</span><span class="p">):</span>
     <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">     Return the square root of n as a fixed point number with the one</span>
<span class="sd">     passed in.  It uses a second order Newton-Raphson convergence.  This</span>
<span class="sd">     doubles the number of significant figures on each iteration.</span>
<span class="sd">     &quot;&quot;&quot;</span>
     <span class="c"># Use floating point arithmetic to make an initial guess</span>
     <span class="n">floating_point_precision</span> <span class="o">=</span> <span class="mi">10</span><span class="o">**</span><span class="mi">16</span>
     <span class="n">n_float</span> <span class="o">=</span> <span class="nb">float</span><span class="p">((</span><span class="n">n</span> <span class="o">*</span> <span class="n">floating_point_precision</span><span class="p">)</span> <span class="o">//</span> <span class="n">one</span><span class="p">)</span> <span class="o">/</span> <span class="n">floating_point_precision</span>
     <span class="n">x</span> <span class="o">=</span> <span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">floating_point_precision</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">n_float</span><span class="p">))</span> <span class="o">*</span> <span class="n">one</span><span class="p">)</span> <span class="o">//</span> <span class="n">floating_point_precision</span>
     <span class="n">n_one</span> <span class="o">=</span> <span class="n">n</span> <span class="o">*</span> <span class="n">one</span>
     <span class="k">while</span> <span class="mi">1</span><span class="p">:</span>
         <span class="n">x_old</span> <span class="o">=</span> <span class="n">x</span>
         <span class="n">x</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">n_one</span> <span class="o">//</span> <span class="n">x</span><span class="p">)</span> <span class="o">//</span> <span class="mi">2</span>
         <span class="k">if</span> <span class="n">x</span> <span class="o">==</span> <span class="n">x_old</span><span class="p">:</span>
             <span class="k">break</span>
     <span class="k">return</span> <span class="n">x</span>
</pre></div>


</div>
<p>It uses normal floating point arithmetic to make an initial guess then refines it using Newton's method.</p>
<p>See <a class="reference external" href="/nick/pub/pymath/pi_chudnovsky.py">pi_chudnovsky.py</a> for the complete program.  When I run it I get this:</p>
<table border="1" class="docutils">
<colgroup>
<col width="22%" />
<col width="78%" />
</colgroup>
<thead valign="bottom">
<tr><th class="head">Digits</th>
<th class="head">Time (seconds)</th>
</tr>
</thead>
<tbody valign="top">
<tr><td>10</td>
<td>4.696e-05</td>
</tr>
<tr><td>100</td>
<td>0.0001530</td>
</tr>
<tr><td>1000</td>
<td>0.002027</td>
</tr>
<tr><td>10000</td>
<td>0.08685</td>
</tr>
<tr><td>100000</td>
<td>8.453</td>
</tr>
<tr><td>1000000</td>
<td>956.3</td>
</tr>
</tbody>
</table>
<p>Which is nearly 3 times quicker than the best result in <a class="reference external" href="/nick/articles/pi-machin/">part 3</a>, and gets us 1,000,000 places of π in about 15 minutes.</p>
<p>Amazingly there are still two major improvements we can make to this.  The first is to recast the calculation using something called <a class="reference external" href="http://numbers.computation.free.fr/Constants/Algorithms/splitting.html">binary splitting</a>.  Binary splitting is a general purpose technique for speeding up this sort of calculation.  What it does is convert the sum of the individual fractions into one giant fraction.  This means that you only do one divide at the end of the calculation which speeds things up greatly, because division is slow compared to multiplication.</p>
<p>Consider the general infinite series</p>
<div class="literal-block"><img class="math" src="/nick/images/math/b1178e265167bde29ef15a32724b03ea.png" alt="\[
S(0,\infty) = \frac{a_0p_0}{b_0q_0}
+ \frac{a_1p_0p_1}{b_1q_0q_1}
+ \frac{a_2p_0p_1p_2}{b_2q_0q_1q_2}
+ \frac{a_3p_0p_1p_2p_3}{b_3q_0q_1q_2q_3}
+ \cdots
\]
" title="\[
S(0,\infty) = \frac{a_0p_0}{b_0q_0}
+ \frac{a_1p_0p_1}{b_1q_0q_1}
+ \frac{a_2p_0p_1p_2}{b_2q_0q_1q_2}
+ \frac{a_3p_0p_1p_2p_3}{b_3q_0q_1q_2q_3}
+ \cdots
\]
" /></div>
<p>This could be used as a model for all the infinite series we've looked at so far.  Now lets consider the partial sum of that series from terms <tt class="docutils literal">a</tt> to <tt class="docutils literal">b</tt> (including a, not including b).</p>
<div class="literal-block"><img class="math" src="/nick/images/math/0ae8576210f112277eb6dd7d26654dc2.png" alt="\begin{eqnarray*}
S(a,b) &amp;=&amp; \frac{a_ap_a}{b_aq_a}
+ \frac{a_{a+1}p_ap_{a+1}}{b_{a+1}q_aq_{a+1}}
+ \frac{a_{a+2}p_ap_{a+1}p_{a+2}}{b_{a+2}q_aq_{a+1}q_{a+2}}
+ \cdots
+ \frac{a_{b-1}p_ap_{a+1}p_{a+2}\cdots p_{b-1}}{b_{b-1}q_aq_{a+1}\cdots p_{b-1}} \\
\end{eqnarray*}
" title="\begin{eqnarray*}
S(a,b) &amp;=&amp; \frac{a_ap_a}{b_aq_a}
+ \frac{a_{a+1}p_ap_{a+1}}{b_{a+1}q_aq_{a+1}}
+ \frac{a_{a+2}p_ap_{a+1}p_{a+2}}{b_{a+2}q_aq_{a+1}q_{a+2}}
+ \cdots
+ \frac{a_{b-1}p_ap_{a+1}p_{a+2}\cdots p_{b-1}}{b_{b-1}q_aq_{a+1}\cdots p_{b-1}} \\
\end{eqnarray*}
" /></div>
<p>This is a part of the infinite series, and if a=0 and b=∞ it becomes the infinite series above.</p>
<p>Now lets define some extra functions:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/35536ada8514635283ff7e59221c0930.png" alt="\begin{eqnarray*}
P(a,b) &amp;=&amp; p_ap_{a+1}\cdots p_{b-1} \\
Q(a,b) &amp;=&amp; q_aq_{a+1}\cdots q_{b-1} \\
B(a,b) &amp;=&amp; b_ab_{a+1}\cdots b_{b-1} \\
T(a,b) &amp;=&amp; B(a,b)Q(a,b)S(a,b) \\
\end{eqnarray*}
" title="\begin{eqnarray*}
P(a,b) &amp;=&amp; p_ap_{a+1}\cdots p_{b-1} \\
Q(a,b) &amp;=&amp; q_aq_{a+1}\cdots q_{b-1} \\
B(a,b) &amp;=&amp; b_ab_{a+1}\cdots b_{b-1} \\
T(a,b) &amp;=&amp; B(a,b)Q(a,b)S(a,b) \\
\end{eqnarray*}
" /></div>
<p>Let's define m which is a &lt;= m &lt;= b.  Making m as near to the middle of a and b will lead to the quickest calculations, but for the proof, it has to be somewhere between them.  Lets work out what happens to our variables P, Q, R and T when we split the series in two:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/0276e92c28290328412e74d26fdfce4e.png" alt="\begin{eqnarray*}
P(a,b) &amp;=&amp; P(a,m)P(b,m) \\
Q(a,b) &amp;=&amp; Q(a,m)Q(b,m) \\
B(a,b) &amp;=&amp; B(a,m)B(b,m) \\
T(a,b) &amp;=&amp; B(m,b)Q(m,b)T(a,m) + B(a,m)P(a,m)T(m,b) \\
\end{eqnarray*}
" title="\begin{eqnarray*}
P(a,b) &amp;=&amp; P(a,m)P(b,m) \\
Q(a,b) &amp;=&amp; Q(a,m)Q(b,m) \\
B(a,b) &amp;=&amp; B(a,m)B(b,m) \\
T(a,b) &amp;=&amp; B(m,b)Q(m,b)T(a,m) + B(a,m)P(a,m)T(m,b) \\
\end{eqnarray*}
" /></div>
<p>The first three of those statements are obvious from the definitions, but the last deserves proof.</p>
<div class="literal-block"><img class="math" src="/nick/images/math/2ba1a65b212b89c3bd3b1f83350a5827.png" alt="\begin{eqnarray*}
\lefteqn{B(m,b)Q(m,b)T(a,m) + B(a,m)P(a,m)T(m,b) = } \\
&amp; &amp; \left[T(a,b) = B(a,b)Q(a,b)S(a,b)\right] \\
&amp;=&amp; B(m,b)Q(m,b)B(a,m)Q(a,m)S(a,m) + B(a,m)P(a,m)B(m,b)Q(m,b)S(m,b) \\
&amp; &amp; \left[Q(a,b) = Q(a,m)Q(b,m)\right] \\
&amp; &amp; \left[B(a,b) = B(a,m)B(b,m)\right] \\
&amp;=&amp; B(a,b)Q(a,b)S(a,m) + B(a,b)P(a,m)Q(m,b)S(m,b) \\
&amp;=&amp; B(a,b)(Q(a,b)S(a,m) + P(a,m)Q(m,b)S(m,b)) \\
&amp; &amp; \left[Q(m,b) = \frac{Q(a,b)}{Q(a,m)}\right] \\
&amp;=&amp; B(a,b)\left(Q(a,b)S(a,m) + \frac{Q(a,b)P(a,m)}{Q(a,m)}S(m,b)\right) \\
&amp;=&amp; B(a,b)Q(a,b)\left(S(a,m) + \frac{P(a,m)}{Q(a,m)}S(m,b)\right) \\
&amp;=&amp; B(a,b)Q(a,b)\left(
\frac{a_ap_a}{b_aq_a}
+ \frac{a_{a+1}p_ap_{a+1}}{b_{a+1}q_aq_{a+1}}
+ \frac{a_{a+2}p_ap_{a+1}p_{a+2}}{b_{a+2}q_aq_{a+1}q_{a+2}}
+ \cdots
+ \frac{a_{m-1}p_ap_{a+1}p_{a+2}\cdots p_{m-1}}{b_{m-1}q_aq_{a+1}\cdots p_{m-1}}
+ \frac{p_ap_{a+1}\cdots p_{m-1}}{q_aq_{a+1}\cdots q_{m-1}}
+ \left(\frac{a_mp_m}{b_mq_m}
+ \frac{a_{m+1}p_mp_{m+1}}{b_{m+1}q_mq_{m+1}}
+ \frac{a_{m+2}p_mp_{m+1}p_{m+2}}{b_{m+2}q_mq_{m+1}q_{m+2}}
+ \cdots
+ \frac{a_{b-1}p_mp_{m+1}p_{m+2}\cdots p_{b-1}}{b_{b-1}q_mq_{m+1}\cdots p_{b-1}}
\right)\right) \\
&amp;=&amp; B(a,b)Q(a,b)\left(
\frac{a_ap_a}{b_aq_a}
+ \frac{a_{a+1}p_ap_{a+1}}{b_{a+1}q_aq_{a+1}}
+ \frac{a_{a+2}p_ap_{a+1}p_{a+2}}{b_{a+2}q_aq_{a+1}q_{a+2}}
+ \cdots
+ \frac{a_{m-1}p_ap_{a+1}p_{a+2}\cdots p_{m-1}}{b_{m-1}q_aq_{a+1}\cdots p_{m-1}}
+ \frac{p_ap_{a+1}\cdots p_{m-1}}{q_aq_{a+1}\cdots q_{m-1}}
+ \frac{a_mp_ap_{a+1}\cdots p_m}{b_mq_aq_{a+1}\cdots q_m}
+ \frac{a_{m+1}p_ap_{a+1}\cdots p_{m+1}}{b_{m+1}q_aq_{a+1}\cdots q_{m+1}}
+ \frac{a_{m+2}p_ap_{a+1}\cdots p_{m+2}}{b_{m+2}q_aq_{a+1}\cdots q_{m+2}}
+ \cdots
+ \frac{a_{b-1}p_ap_{a+1}\cdots p_{b-1}}{b_{b-1}q_aq_{a+1}\cdots p_{b-1}}
\right) \\
&amp;=&amp; B(a,b)Q(a,b)S(a,b) \\
&amp;=&amp; T(a,b) \\
\end{eqnarray*}
" title="\begin{eqnarray*}
\lefteqn{B(m,b)Q(m,b)T(a,m) + B(a,m)P(a,m)T(m,b) = } \\
&amp; &amp; \left[T(a,b) = B(a,b)Q(a,b)S(a,b)\right] \\
&amp;=&amp; B(m,b)Q(m,b)B(a,m)Q(a,m)S(a,m) + B(a,m)P(a,m)B(m,b)Q(m,b)S(m,b) \\
&amp; &amp; \left[Q(a,b) = Q(a,m)Q(b,m)\right] \\
&amp; &amp; \left[B(a,b) = B(a,m)B(b,m)\right] \\
&amp;=&amp; B(a,b)Q(a,b)S(a,m) + B(a,b)P(a,m)Q(m,b)S(m,b) \\
&amp;=&amp; B(a,b)(Q(a,b)S(a,m) + P(a,m)Q(m,b)S(m,b)) \\
&amp; &amp; \left[Q(m,b) = \frac{Q(a,b)}{Q(a,m)}\right] \\
&amp;=&amp; B(a,b)\left(Q(a,b)S(a,m) + \frac{Q(a,b)P(a,m)}{Q(a,m)}S(m,b)\right) \\
&amp;=&amp; B(a,b)Q(a,b)\left(S(a,m) + \frac{P(a,m)}{Q(a,m)}S(m,b)\right) \\
&amp;=&amp; B(a,b)Q(a,b)\left(
\frac{a_ap_a}{b_aq_a}
+ \frac{a_{a+1}p_ap_{a+1}}{b_{a+1}q_aq_{a+1}}
+ \frac{a_{a+2}p_ap_{a+1}p_{a+2}}{b_{a+2}q_aq_{a+1}q_{a+2}}
+ \cdots
+ \frac{a_{m-1}p_ap_{a+1}p_{a+2}\cdots p_{m-1}}{b_{m-1}q_aq_{a+1}\cdots p_{m-1}}
+ \frac{p_ap_{a+1}\cdots p_{m-1}}{q_aq_{a+1}\cdots q_{m-1}}
+ \left(\frac{a_mp_m}{b_mq_m}
+ \frac{a_{m+1}p_mp_{m+1}}{b_{m+1}q_mq_{m+1}}
+ \frac{a_{m+2}p_mp_{m+1}p_{m+2}}{b_{m+2}q_mq_{m+1}q_{m+2}}
+ \cdots
+ \frac{a_{b-1}p_mp_{m+1}p_{m+2}\cdots p_{b-1}}{b_{b-1}q_mq_{m+1}\cdots p_{b-1}}
\right)\right) \\
&amp;=&amp; B(a,b)Q(a,b)\left(
\frac{a_ap_a}{b_aq_a}
+ \frac{a_{a+1}p_ap_{a+1}}{b_{a+1}q_aq_{a+1}}
+ \frac{a_{a+2}p_ap_{a+1}p_{a+2}}{b_{a+2}q_aq_{a+1}q_{a+2}}
+ \cdots
+ \frac{a_{m-1}p_ap_{a+1}p_{a+2}\cdots p_{m-1}}{b_{m-1}q_aq_{a+1}\cdots p_{m-1}}
+ \frac{p_ap_{a+1}\cdots p_{m-1}}{q_aq_{a+1}\cdots q_{m-1}}
+ \frac{a_mp_ap_{a+1}\cdots p_m}{b_mq_aq_{a+1}\cdots q_m}
+ \frac{a_{m+1}p_ap_{a+1}\cdots p_{m+1}}{b_{m+1}q_aq_{a+1}\cdots q_{m+1}}
+ \frac{a_{m+2}p_ap_{a+1}\cdots p_{m+2}}{b_{m+2}q_aq_{a+1}\cdots q_{m+2}}
+ \cdots
+ \frac{a_{b-1}p_ap_{a+1}\cdots p_{b-1}}{b_{b-1}q_aq_{a+1}\cdots p_{b-1}}
\right) \\
&amp;=&amp; B(a,b)Q(a,b)S(a,b) \\
&amp;=&amp; T(a,b) \\
\end{eqnarray*}
" /></div>
<p>We can use these relations to expand the series recursively, so if we
want S(0,8) then we can work out S(0,4) and S(4,8) and combine them.
Likewise to calculate S(0,4) and S(4,8) we work out S(0,2), S(2,4),
S(4,6), S(6,8) and combine them, and to work out those we work out
S(0,1), S(1,2), S(2,3), S(3,4), S(4,5), S(5,6), S(6,7), S(7,8).
Luckily we don't have to split them down any more as we know what
P(a,a+1), Q(a,a+1) etc is from the definition above.</p>
<div class="literal-block"><img class="math" src="/nick/images/math/8410222e55da96c9136e9ef783ba8e8e.png" alt="\begin{eqnarray*}
P(a,a+1) &amp;=&amp; p_a \\
Q(a,a+1) &amp;=&amp; q_a \\
B(a,a+1) &amp;=&amp; b_a \\
S(a,a+1) &amp;=&amp; \frac{a_ap_a}{b_aq_a} \\
T(a,a+1) &amp;=&amp; B(a,a+1)Q(a,a+1)S(a,a+1) \\
         &amp;=&amp; b_aq_a\frac{a_ap_a}{b_aq_a} \\
         &amp;=&amp; a_ap_a \\
\end{eqnarray*}
" title="\begin{eqnarray*}
P(a,a+1) &amp;=&amp; p_a \\
Q(a,a+1) &amp;=&amp; q_a \\
B(a,a+1) &amp;=&amp; b_a \\
S(a,a+1) &amp;=&amp; \frac{a_ap_a}{b_aq_a} \\
T(a,a+1) &amp;=&amp; B(a,a+1)Q(a,a+1)S(a,a+1) \\
         &amp;=&amp; b_aq_a\frac{a_ap_a}{b_aq_a} \\
         &amp;=&amp; a_ap_a \\
\end{eqnarray*}
" /></div>
<p>And when you've finally worked out P(0,n),Q(0,n),B(0,n),T(0,n) you can work out S(0,n) with</p>
<div class="literal-block"><img class="math" src="/nick/images/math/ff484f49ec59db770c2fb31a9d00b810.png" alt="\begin{eqnarray*}
S(0,n) &amp;=&amp; \frac{T(0,n)}{B(0,n)Q(0,n)} \\
\end{eqnarray*}
" title="\begin{eqnarray*}
S(0,n) &amp;=&amp; \frac{T(0,n)}{B(0,n)Q(0,n)} \\
\end{eqnarray*}
" /></div>
<p>If you want a more detailed and precise treatment of binary splitting then see <a class="reference external" href="http://www.ginac.de/CLN/binsplit.pdf">Bruno Haible and Thomas Papanikolaou's paper</a>.</p>
<p>So back to Chudnovksy's series.  We can now set these parameters in the above general formula:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/4514a03b73606bb2109ec074174b7064.png" alt="\begin{eqnarray*}
p_0 &amp;=&amp; 1 \\
p_a &amp;=&amp; (6a-5)(2a-1)(6a-1) \\
q_0 &amp;=&amp; 1 \\
q_a &amp;=&amp; a^3\cdot640320^3/24 \\
b_a &amp;=&amp; 1 \\
a_a &amp;=&amp; (13591409 + 545140134a) \\
\end{eqnarray*}
" title="\begin{eqnarray*}
p_0 &amp;=&amp; 1 \\
p_a &amp;=&amp; (6a-5)(2a-1)(6a-1) \\
q_0 &amp;=&amp; 1 \\
q_a &amp;=&amp; a^3\cdot640320^3/24 \\
b_a &amp;=&amp; 1 \\
a_a &amp;=&amp; (13591409 + 545140134a) \\
\end{eqnarray*}
" /></div>
<p>This then makes our Chudnovksy pi function look like this:</p>
<div class="literal-block">

<div class="pygments_murphy"><pre><span class="k">def</span> <span class="nf">pi_chudnovsky_bs</span><span class="p">(</span><span class="n">digits</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Compute int(pi * 10**digits)</span>

<span class="sd">    This is done using Chudnovsky&#39;s series with binary splitting</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">C</span> <span class="o">=</span> <span class="mi">640320</span>
    <span class="n">C3_OVER_24</span> <span class="o">=</span> <span class="n">C</span><span class="o">**</span><span class="mi">3</span> <span class="o">//</span> <span class="mi">24</span>
    <span class="k">def</span> <span class="nf">bs</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Computes the terms for binary splitting the Chudnovsky infinite series</span>

<span class="sd">        a(a) = +/- (13591409 + 545140134*a)</span>
<span class="sd">        p(a) = (6*a-5)*(2*a-1)*(6*a-1)</span>
<span class="sd">        b(a) = 1</span>
<span class="sd">        q(a) = a*a*a*C3_OVER_24</span>

<span class="sd">        returns P(a,b), Q(a,b) and T(a,b)</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="n">b</span> <span class="o">-</span> <span class="n">a</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
            <span class="c"># Directly compute P(a,a+1), Q(a,a+1) and T(a,a+1)</span>
            <span class="k">if</span> <span class="n">a</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                <span class="n">Pab</span> <span class="o">=</span> <span class="n">Qab</span> <span class="o">=</span> <span class="mi">1</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">Pab</span> <span class="o">=</span> <span class="p">(</span><span class="mi">6</span><span class="o">*</span><span class="n">a</span><span class="o">-</span><span class="mi">5</span><span class="p">)</span><span class="o">*</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">a</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="p">(</span><span class="mi">6</span><span class="o">*</span><span class="n">a</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
                <span class="n">Qab</span> <span class="o">=</span> <span class="n">a</span><span class="o">*</span><span class="n">a</span><span class="o">*</span><span class="n">a</span><span class="o">*</span><span class="n">C3_OVER_24</span>
            <span class="n">Tab</span> <span class="o">=</span> <span class="n">Pab</span> <span class="o">*</span> <span class="p">(</span><span class="mi">13591409</span> <span class="o">+</span> <span class="mi">545140134</span><span class="o">*</span><span class="n">a</span><span class="p">)</span> <span class="c"># a(a) * p(a)</span>
            <span class="k">if</span> <span class="n">a</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">:</span>
                <span class="n">Tab</span> <span class="o">=</span> <span class="o">-</span><span class="n">Tab</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c"># Recursively compute P(a,b), Q(a,b) and T(a,b)</span>
            <span class="c"># m is the midpoint of a and b</span>
            <span class="n">m</span> <span class="o">=</span> <span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span> <span class="o">//</span> <span class="mi">2</span>
            <span class="c"># Recursively calculate P(a,m), Q(a,m) and T(a,m)</span>
            <span class="n">Pam</span><span class="p">,</span> <span class="n">Qam</span><span class="p">,</span> <span class="n">Tam</span> <span class="o">=</span> <span class="n">bs</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">m</span><span class="p">)</span>
            <span class="c"># Recursively calculate P(m,b), Q(m,b) and T(m,b)</span>
            <span class="n">Pmb</span><span class="p">,</span> <span class="n">Qmb</span><span class="p">,</span> <span class="n">Tmb</span> <span class="o">=</span> <span class="n">bs</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
            <span class="c"># Now combine</span>
            <span class="n">Pab</span> <span class="o">=</span> <span class="n">Pam</span> <span class="o">*</span> <span class="n">Pmb</span>
            <span class="n">Qab</span> <span class="o">=</span> <span class="n">Qam</span> <span class="o">*</span> <span class="n">Qmb</span>
            <span class="n">Tab</span> <span class="o">=</span> <span class="n">Qmb</span> <span class="o">*</span> <span class="n">Tam</span> <span class="o">+</span> <span class="n">Pam</span> <span class="o">*</span> <span class="n">Tmb</span>
        <span class="k">return</span> <span class="n">Pab</span><span class="p">,</span> <span class="n">Qab</span><span class="p">,</span> <span class="n">Tab</span>
    <span class="c"># how many terms to compute</span>
    <span class="n">DIGITS_PER_TERM</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">log10</span><span class="p">(</span><span class="n">C3_OVER_24</span><span class="o">/</span><span class="mi">6</span><span class="o">/</span><span class="mi">2</span><span class="o">/</span><span class="mi">6</span><span class="p">)</span>
    <span class="n">N</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">digits</span><span class="o">/</span><span class="n">DIGITS_PER_TERM</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
    <span class="c"># Calclate P(0,N) and Q(0,N)</span>
    <span class="n">P</span><span class="p">,</span> <span class="n">Q</span><span class="p">,</span> <span class="n">T</span> <span class="o">=</span> <span class="n">bs</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">N</span><span class="p">)</span>
    <span class="n">one</span> <span class="o">=</span> <span class="mi">10</span><span class="o">**</span><span class="n">digits</span>
    <span class="n">sqrtC</span> <span class="o">=</span> <span class="n">sqrt</span><span class="p">(</span><span class="mi">10005</span><span class="o">*</span><span class="n">one</span><span class="p">,</span> <span class="n">one</span><span class="p">)</span>
    <span class="k">return</span> <span class="p">(</span><span class="n">Q</span><span class="o">*</span><span class="mi">426880</span><span class="o">*</span><span class="n">sqrtC</span><span class="p">)</span> <span class="o">//</span> <span class="n">T</span>
</pre></div>


</div>
<p>Hopefully you'll see how the maths above relates to this as I've used
the same notation in each.  Note that we calculate the number of
digits of pi we expect per term of the series (about 14.18) to work
out how many terms of the series we need to compute, as the binary
splitting algorithm needs to know in advance how many terms to
calculate.  We also don't bother calculating <tt class="docutils literal">B(a)</tt> as it is always
<tt class="docutils literal">1</tt>.  Defining a function inside a function like this makes what is
known as a closure.  This means that the inner function can access the
variables in the outer function which is very convenient in this
recursive algorithm as it stops us having to pass the constants to
every call of the function.</p>
<p>See <a class="reference external" href="/nick/pub/pymath/pi_chudnovsky_bs.py">pi_chudnovsky_bs.py</a> for the complete program.  When I run it I get this:</p>
<table border="1" class="docutils">
<colgroup>
<col width="22%" />
<col width="78%" />
</colgroup>
<thead valign="bottom">
<tr><th class="head">Digits</th>
<th class="head">Time (seconds)</th>
</tr>
</thead>
<tbody valign="top">
<tr><td>10</td>
<td>1.096e-05</td>
</tr>
<tr><td>100</td>
<td>3.194e-05</td>
</tr>
<tr><td>1000</td>
<td>0.0004899</td>
</tr>
<tr><td>10000</td>
<td>0.03403</td>
</tr>
<tr><td>100000</td>
<td>3.625</td>
</tr>
<tr><td>1000000</td>
<td>419.1</td>
</tr>
</tbody>
</table>
<p>This is a bit more than twice as fast as <a class="reference external" href="/nick/pub/pymath/pi_chudnovsky.py">pi_chudnovsky.py</a> giving us
our 1,000,000 places in just under 7 minutes.  If you profile it
you'll discover that almost all the time spent in the square root
calculations (86% of the time) whereas only 56 seconds is spent in
the binary splitting part.  We could spend time improving the square
root algorithm, but it is time to bring out the big guns: gmpy.</p>
<p><a class="reference external" href="https://code.google.com/p/gmpy/">Gmpy</a> is a python interface to the <a class="reference external" href="http://gmplib.org/">gmp library</a> which is a C library
for arbitrary precision arithmetic.  It is very fast, much faster than
the built in <tt class="docutils literal">int</tt> type in python for large numbers. Luckily gmpy
provides a type (<tt class="docutils literal">mpz</tt>) which works exactly like normal python
<tt class="docutils literal">int</tt> types, so we have to make hardly any changes to our code to
use it.  These are using initialising variables with the <tt class="docutils literal">mpz</tt> type,
and using the <tt class="docutils literal">sqrt</tt> method on <tt class="docutils literal">mpz</tt> rather than our own home made
<tt class="docutils literal">sqrt</tt> algorithm:</p>
<div class="literal-block">

<div class="pygments_murphy"><pre><span class="kn">import</span> <span class="nn">math</span>
<span class="kn">from</span> <span class="nn">gmpy2</span> <span class="kn">import</span> <span class="n">mpz</span>
<span class="kn">from</span> <span class="nn">time</span> <span class="kn">import</span> <span class="n">time</span>

<span class="k">def</span> <span class="nf">pi_chudnovsky_bs</span><span class="p">(</span><span class="n">digits</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Compute int(pi * 10**digits)</span>

<span class="sd">    This is done using Chudnovsky&#39;s series with binary splitting</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">C</span> <span class="o">=</span> <span class="mi">640320</span>
    <span class="n">C3_OVER_24</span> <span class="o">=</span> <span class="n">C</span><span class="o">**</span><span class="mi">3</span> <span class="o">//</span> <span class="mi">24</span>
    <span class="k">def</span> <span class="nf">bs</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Computes the terms for binary splitting the Chudnovsky infinite series</span>

<span class="sd">        a(a) = +/- (13591409 + 545140134*a)</span>
<span class="sd">        p(a) = (6*a-5)*(2*a-1)*(6*a-1)</span>
<span class="sd">        b(a) = 1</span>
<span class="sd">        q(a) = a*a*a*C3_OVER_24</span>

<span class="sd">        returns P(a,b), Q(a,b) and T(a,b)</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="n">b</span> <span class="o">-</span> <span class="n">a</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
            <span class="c"># Directly compute P(a,a+1), Q(a,a+1) and T(a,a+1)</span>
            <span class="k">if</span> <span class="n">a</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                <span class="n">Pab</span> <span class="o">=</span> <span class="n">Qab</span> <span class="o">=</span> <span class="n">mpz</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">Pab</span> <span class="o">=</span> <span class="n">mpz</span><span class="p">((</span><span class="mi">6</span><span class="o">*</span><span class="n">a</span><span class="o">-</span><span class="mi">5</span><span class="p">)</span><span class="o">*</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">a</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="p">(</span><span class="mi">6</span><span class="o">*</span><span class="n">a</span><span class="o">-</span><span class="mi">1</span><span class="p">))</span>
                <span class="n">Qab</span> <span class="o">=</span> <span class="n">mpz</span><span class="p">(</span><span class="n">a</span><span class="o">*</span><span class="n">a</span><span class="o">*</span><span class="n">a</span><span class="o">*</span><span class="n">C3_OVER_24</span><span class="p">)</span>
            <span class="n">Tab</span> <span class="o">=</span> <span class="n">Pab</span> <span class="o">*</span> <span class="p">(</span><span class="mi">13591409</span> <span class="o">+</span> <span class="mi">545140134</span><span class="o">*</span><span class="n">a</span><span class="p">)</span> <span class="c"># a(a) * p(a)</span>
            <span class="k">if</span> <span class="n">a</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">:</span>
                <span class="n">Tab</span> <span class="o">=</span> <span class="o">-</span><span class="n">Tab</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c"># Recursively compute P(a,b), Q(a,b) and T(a,b)</span>
            <span class="c"># m is the midpoint of a and b</span>
            <span class="n">m</span> <span class="o">=</span> <span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span> <span class="o">//</span> <span class="mi">2</span>
            <span class="c"># Recursively calculate P(a,m), Q(a,m) and T(a,m)</span>
            <span class="n">Pam</span><span class="p">,</span> <span class="n">Qam</span><span class="p">,</span> <span class="n">Tam</span> <span class="o">=</span> <span class="n">bs</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">m</span><span class="p">)</span>
            <span class="c"># Recursively calculate P(m,b), Q(m,b) and T(m,b)</span>
            <span class="n">Pmb</span><span class="p">,</span> <span class="n">Qmb</span><span class="p">,</span> <span class="n">Tmb</span> <span class="o">=</span> <span class="n">bs</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
            <span class="c"># Now combine</span>
            <span class="n">Pab</span> <span class="o">=</span> <span class="n">Pam</span> <span class="o">*</span> <span class="n">Pmb</span>
            <span class="n">Qab</span> <span class="o">=</span> <span class="n">Qam</span> <span class="o">*</span> <span class="n">Qmb</span>
            <span class="n">Tab</span> <span class="o">=</span> <span class="n">Qmb</span> <span class="o">*</span> <span class="n">Tam</span> <span class="o">+</span> <span class="n">Pam</span> <span class="o">*</span> <span class="n">Tmb</span>
        <span class="k">return</span> <span class="n">Pab</span><span class="p">,</span> <span class="n">Qab</span><span class="p">,</span> <span class="n">Tab</span>
    <span class="c"># how many terms to compute</span>
    <span class="n">DIGITS_PER_TERM</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">log10</span><span class="p">(</span><span class="n">C3_OVER_24</span><span class="o">/</span><span class="mi">6</span><span class="o">/</span><span class="mi">2</span><span class="o">/</span><span class="mi">6</span><span class="p">)</span>
    <span class="n">N</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">digits</span><span class="o">/</span><span class="n">DIGITS_PER_TERM</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
    <span class="c"># Calclate P(0,N) and Q(0,N)</span>
    <span class="n">P</span><span class="p">,</span> <span class="n">Q</span><span class="p">,</span> <span class="n">T</span> <span class="o">=</span> <span class="n">bs</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">N</span><span class="p">)</span>
    <span class="n">one_squared</span> <span class="o">=</span> <span class="n">mpz</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span><span class="o">**</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">digits</span><span class="p">)</span>
    <span class="n">sqrtC</span> <span class="o">=</span> <span class="p">(</span><span class="mi">10005</span><span class="o">*</span><span class="n">one_squared</span><span class="p">)</span><span class="o">.</span><span class="n">sqrt</span><span class="p">()</span>
    <span class="k">return</span> <span class="p">(</span><span class="n">Q</span><span class="o">*</span><span class="mi">426880</span><span class="o">*</span><span class="n">sqrtC</span><span class="p">)</span> <span class="o">//</span> <span class="n">T</span>
</pre></div>


</div>
<p>See <a class="reference external" href="/nick/pub/pymath/pi_chudnovsky_bs_gmpy.py">pi_chudnovsky_bs_gmpy.py</a> for the complete program.  When I run it I get this:</p>
<table border="1" class="docutils">
<colgroup>
<col width="26%" />
<col width="74%" />
</colgroup>
<thead valign="bottom">
<tr><th class="head">Digits</th>
<th class="head">Time (seconds)</th>
</tr>
</thead>
<tbody valign="top">
<tr><td>10</td>
<td>1.597e-05</td>
</tr>
<tr><td>100</td>
<td>3.409e-05</td>
</tr>
<tr><td>1000</td>
<td>0.003403</td>
</tr>
<tr><td>10000</td>
<td>0.003571</td>
</tr>
<tr><td>100000</td>
<td>0.09120</td>
</tr>
<tr><td>1000000</td>
<td>1.760</td>
</tr>
<tr><td>10000000</td>
<td>30.11</td>
</tr>
<tr><td>100000000</td>
<td>542.2</td>
</tr>
</tbody>
</table>
<p>So we have achieved our goal of calculating 100,000,000 places
of π in just under 10 minutes!  What is limiting the program now is
memory...  100,000,000 places takes about 600MB of memory to run.
With 6 GB of free memory it could probably calculate one billion
places in a few hours.</p>
<p>What if we wanted to go faster?  Well you could use
<a class="reference external" href="ftp://ftp.gmplib.org/pub/misc/gmp-chudnovsky.c">gmp-chudnovsky.c</a> which is a C program which implements the
Chudnovsky Algorithm.  It is heavily optimised and rather difficult to
understand, but if you untangle it you'll see it does exactly the same
as above, with one extra twist.  The twist is that it factors the
fraction in the binary splitting phase as it goes along.  If you
examine the <a class="reference external" href="http://gmplib.org/pi-with-gmp.html">gmp-chudnovsky.c results</a> page you'll see that the
little python program above acquits itself very well - the python
program only takes 75% longer than the optimised C program on the same
hardware.</p>
<p>One algorithm which has the potential to beat Chudnovsky is the
<a class="reference external" href="http://en.wikipedia.org/wiki/Gauss-Legendre_algorithm">Arithmetic Geometric Mean</a> algorithm which doubles the number of
decimal places each iteration.  It involves square roots and full
precision divisions which makes it tricky to implement well.  In
theory it should be faster than Chudnovsk but, so far, in practice
Chudnovsky is faster.</p>
<p>Here is a chart of all the different π programs we've developed in
<a class="reference external" href="/nick/articles/pi-gregorys-series/">Part 1</a>, <a class="reference external" href="/nick/articles/pi-archimedes/">Part 2</a>, <a class="reference external" href="/nick/articles/pi-machin/">Part 3</a> and <a class="reference external" href="/nick/articles/pi-chudnovsky/">Part 4</a> with their timings on my
2010 Intel® Core™ i7 CPU Q820 &#64; 1.73GHz running 64 bit Linux:</p>
<img alt="Chart of timings for calculating π with various methods" src="/nick/pub/pymath/pi_timings.png" />
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Pi - Machin</title>
      <link>http://www.craig-wood.com/nick/articles/pi-machin</link>
      <pubDate>Tue, 19 Jul 2011 00:00:00 BST</pubDate>
      <category><![CDATA[maths]]></category>
      <category><![CDATA[pymath]]></category>
      <category><![CDATA[python]]></category>
      <guid>http://www.craig-wood.com/nick/articles/pi-machin</guid>
      <description>Pi - Machin</description>
      <content:encoded><![CDATA[<div class="document">
<p>In <a class="reference external" href="/nick/articles/pi-archimedes/">Part 2</a> we managed to calculate 100 decimal places of π with Archimedes' recurrence relation for π which was a fine result, but we can do bigger and faster.</p>
<div class="sidebar">
<p class="first sidebar-title">Fun with Maths and Python</p>
<p class="last">This is a having fun with maths and python article.  See <a class="reference external" href="/nick/articles/fun-with-maths-and-python-introduction/">the introduction</a> for important information!</p>
</div>
<p>To go faster we'll have to use a two pronged approach - a better algorithm for π, and a better implementation.</p>
<p>In 1706 <a class="reference external" href="http://en.wikipedia.org/wiki/John_Machin">John Machin</a> came up with the first really fast method of calculating π and used it to calculate π to 100 decimal places.  Quite an achievement considering he did that entirely with pencil and paper.  Machin's formula is:</p>
<pre class="literal-block">
π/4 = 4cot⁻¹(5) - cot⁻¹(239)
    = 4tan⁻¹(1/5) - tan⁻¹(1/239)
    = 4 * arctan(1/5) - arctan(1/239)
</pre>
<p>We can prove Machin's formula using some relatively easy math!  Hopefully you learnt this <a class="reference external" href="http://mathworld.wolfram.com/TrigonometricAdditionFormulas.html">trigonometric formula</a> at school:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/ba59c45582fef5d43cb00b4239b38ea4.png" alt="\[
tan(a + b) = \frac{tan(a) + tan(b)}{1 - tan(a) \cdot tan(b)}
\]
" title="\[
tan(a + b) = \frac{tan(a) + tan(b)}{1 - tan(a) \cdot tan(b)}
\]
" /></div>
<p>Substitute <tt class="docutils literal">a = arctan(x)</tt> and <tt class="docutils literal">b = arctan(y)</tt> into it, giving:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/fe543c13b0d71c92c76a4d793965744b.png" alt="\[
tan(arctan(x) + arctan(y)) = \frac{tan(arctan(x)) + tan(arctan(y)}{1 - tan(arctan(x)) \cdot tan(arctan(y))}
\]
" title="\[
tan(arctan(x) + arctan(y)) = \frac{tan(arctan(x)) + tan(arctan(y)}{1 - tan(arctan(x)) \cdot tan(arctan(y))}
\]
" /></div>
<p>Note that <tt class="docutils literal">tan(arctan(x))</tt> = <tt class="docutils literal">x</tt> which gives:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/141c9b63ef2ce9bc7b029f6e7f19121c.png" alt="\[
tan(arctan(x) + arctan(y)) = \frac{x + y}{1 - xy}
\]
" title="\[
tan(arctan(x) + arctan(y)) = \frac{x + y}{1 - xy}
\]
" /></div>
<p>arctan both sides to get:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/35c7a3b474febc099202d94d8d6884af.png" alt="\[
arctan(x) + arctan(y) = arctan\left(\frac{x + y}{1 - xy}\right)
\]
" title="\[
arctan(x) + arctan(y) = arctan\left(\frac{x + y}{1 - xy}\right)
\]
" /></div>
<p>This gives us a method for adding two <tt class="docutils literal">arctans</tt>.  Using this we can prove Machin's formula with a bit of help from python's <a class="reference external" href="http://docs.python.org/library/fractions.html">fractions module</a>:</p>
<pre class="literal-block">
&gt;&gt;&gt; from fractions import Fraction
&gt;&gt;&gt; def add_arctan(x, y): return (x + y) / (1 - x * y)
...
&gt;&gt;&gt; a = add_arctan(Fraction(1,5), Fraction(1,5))
&gt;&gt;&gt; a # 2*arctan(1/5)
Fraction(5, 12)
&gt;&gt;&gt; b = add_arctan(a, a)
&gt;&gt;&gt; b # 4*arctan(1/5)
Fraction(120, 119)
&gt;&gt;&gt; c = add_arctan(b, Fraction(-1,239))
&gt;&gt;&gt; c # 4*arctan(1/5) - arctan(1/239)
Fraction(1, 1)
&gt;&gt;&gt;
</pre>
<p>So Machin's formula is equal to <tt class="docutils literal">arctan(1/1)</tt> = π/4 QED!  Or if you prefer it written out in mathematical notation:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/3d31711aae1bbc4df46c9d30d521d3ba.png" alt="\begin{eqnarray*}
4arctan\left(\frac{1}{5}\right) - arctan\left(\frac{1}{239}\right)
  &amp;=&amp; 2\left(arctan\left(\frac{1}{5}\right) + arctan\left(\frac{1}{5}\right)\right) - arctan\left(\frac{1}{239}\right) \\
  &amp;=&amp; 2arctan\left(\frac{5}{12}\right) - arctan\left(\frac{1}{239}\right) \\
  &amp;=&amp; arctan\left(\frac{5}{12}\right) + arctan\left(\frac{5}{12}\right) - arctan\left(\frac{1}{239}\right) \\
  &amp;=&amp; arctan\left(\frac{120}{119}\right) - arctan\left(\frac{1}{239}\right) \\
  &amp;=&amp; arctan\left(\frac{1}{1}\right) \\
  &amp;=&amp; \frac{\pi}{4} \\
\end{eqnarray*}
" title="\begin{eqnarray*}
4arctan\left(\frac{1}{5}\right) - arctan\left(\frac{1}{239}\right)
  &amp;=&amp; 2\left(arctan\left(\frac{1}{5}\right) + arctan\left(\frac{1}{5}\right)\right) - arctan\left(\frac{1}{239}\right) \\
  &amp;=&amp; 2arctan\left(\frac{5}{12}\right) - arctan\left(\frac{1}{239}\right) \\
  &amp;=&amp; arctan\left(\frac{5}{12}\right) + arctan\left(\frac{5}{12}\right) - arctan\left(\frac{1}{239}\right) \\
  &amp;=&amp; arctan\left(\frac{120}{119}\right) - arctan\left(\frac{1}{239}\right) \\
  &amp;=&amp; arctan\left(\frac{1}{1}\right) \\
  &amp;=&amp; \frac{\pi}{4} \\
\end{eqnarray*}
" /></div>
<p>So how do we use Machin's formula to calculate π?  Well first we need to calculate <tt class="docutils literal">arctan(x)</tt> which sounds complicated, but we've seen the infinite series for it already in <a class="reference external" href="/nick/articles/pi-gregorys-series/">Part 1</a> :</p>
<div class="literal-block"><img class="math" src="/nick/images/math/f4ec0d0c341574593cce1f5f41c5737a.png" alt="\[
arctan(x) = x - \frac{x^3}{3} + \frac{x^5}{5} - \frac{x^7}{7} + \frac{x^9}{9} - \cdots ( -1 &lt;= x &lt;= 1 )
\]
" title="\[
arctan(x) = x - \frac{x^3}{3} + \frac{x^5}{5} - \frac{x^7}{7} + \frac{x^9}{9} - \cdots ( -1 &lt;= x &lt;= 1 )
\]
" /></div>
<p>We can see that if x=1/5 then the terms get smaller very quickly, which means that the series will converge quickly.  Let's substitute <tt class="docutils literal">x = 1/x</tt> and get:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/1a80bfa0baaf1b2171d10afda4973766.png" alt="\[
arctan(1/x) = \frac{1}{x} - \frac{1}{3x^3} + \frac{1}{5x^5} - \frac{1}{7x^7} + \frac{1}{9x^9} - \cdots ( x &gt;= 1 )
\]
" title="\[
arctan(1/x) = \frac{1}{x} - \frac{1}{3x^3} + \frac{1}{5x^5} - \frac{1}{7x^7} + \frac{1}{9x^9} - \cdots ( x &gt;= 1 )
\]
" /></div>
<p>Each term in the series is created by dividing the previous term by a small integer.  Dividing two 100 digit numbers is hard work as I'm sure you can imagine from your experiences with long division at school!  However it is much easier to divide a short number (a single digit) into a 100 digit number.  We called this short division at school, and that is the key to making a much faster π algorithm.  In fact if you are dividing an N digit number by an M digit number it takes rougly N*M operations.  That square root we did in <a class="reference external" href="/nick/articles/pi-archimedes/">Part 2</a> did dozens of divisions of 200 digit numbers.  So if we could somehow represent the current term in a <tt class="docutils literal">int</tt> <a class="footnote-reference" href="#id4" id="id1">[1]</a> then we could use this speedy division to greatly speed up the calculation.</p>
<p>The way we do that is to multiply everything by a large number, lets say 10 <sup>100</sup>.  We then do all our calculations with integers, knowing that we should shift the decimal place 100 places to the left when done to get the answer.  This needs a little bit of care, but is a well known technique known as fixed point arithmetic.</p>
<p>The definition of the <tt class="docutils literal">arctan(1/x)</tt> function then looks like this:</p>
<div class="literal-block">

<div class="pygments_murphy"><pre><span class="k">def</span> <span class="nf">arctan</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">one</span><span class="o">=</span><span class="mi">1000000</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Calculate arctan(1/x)</span>

<span class="sd">    arctan(1/x) = 1/x - 1/3*x**3 + 1/5*x**5 - ... (x &gt;= 1)</span>

<span class="sd">    This calculates it in fixed point, using the value for one passed in</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">power</span> <span class="o">=</span> <span class="n">one</span> <span class="o">//</span> <span class="n">x</span>            <span class="c"># the +/- 1/x**n part of the term</span>
    <span class="n">total</span> <span class="o">=</span> <span class="n">power</span>               <span class="c"># the total so far</span>
    <span class="n">x_squared</span> <span class="o">=</span> <span class="n">x</span> <span class="o">*</span> <span class="n">x</span>           <span class="c"># precalculate x**2</span>
    <span class="n">divisor</span> <span class="o">=</span> <span class="mi">1</span>                 <span class="c"># the 1,3,5,7 part of the divisor</span>
    <span class="k">while</span> <span class="mi">1</span><span class="p">:</span>
        <span class="n">power</span> <span class="o">=</span> <span class="o">-</span> <span class="n">power</span> <span class="o">//</span> <span class="n">x_squared</span>
        <span class="n">divisor</span> <span class="o">+=</span> <span class="mi">2</span>
        <span class="n">delta</span> <span class="o">=</span> <span class="n">power</span> <span class="o">//</span> <span class="n">divisor</span>
        <span class="k">if</span> <span class="n">delta</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">break</span>
        <span class="n">total</span> <span class="o">+=</span> <span class="n">delta</span>
    <span class="k">return</span> <span class="n">total</span>
</pre></div>


</div>
<p>The value <tt class="docutils literal">one</tt> passed in is the multiplication factor as described above.  You can think of it as representing <tt class="docutils literal">1</tt> in the fixed point arithmetic world.  Note the use of the <tt class="docutils literal">//</tt> operator which does integer divisions.  If you don't use this then python will make floating point values <a class="footnote-reference" href="#id5" id="id2">[2]</a>.  In the loop there are two divisions, <tt class="docutils literal">power // x_squared</tt> and <tt class="docutils literal">power // divisor</tt>.  Both of these will be dividing by small numbers, <tt class="docutils literal">x_squared</tt> will  be 5² = 25 or 239² = 57121 and <tt class="docutils literal">divisor</tt> will be 2 * the number of iterations which again will be small.</p>
<p>So how does this work in practice?  On my machine it calculates 100 digits of π in 0.18 ms which is over 30,000 times faster than the previous calculation with the decimal module in <a class="reference external" href="/nick/articles/pi-archimedes/">Part 2</a>!</p>
<p>Can we do better?</p>
<p>Well the answer is yes!  Firstly there are better arctan formulae.  Amazingly there are other formulae which will calculate π too, like these, which are named after their inventors:</p>
<div class="literal-block">

<div class="pygments_murphy"><pre><span class="k">def</span> <span class="nf">pi_machin</span><span class="p">(</span><span class="n">one</span><span class="p">):</span>
    <span class="k">return</span> <span class="mi">4</span><span class="o">*</span><span class="p">(</span><span class="mi">4</span><span class="o">*</span><span class="n">arctan</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">one</span><span class="p">)</span> <span class="o">-</span> <span class="n">arctan</span><span class="p">(</span><span class="mi">239</span><span class="p">,</span> <span class="n">one</span><span class="p">))</span>

<span class="k">def</span> <span class="nf">pi_ferguson</span><span class="p">(</span><span class="n">one</span><span class="p">):</span>
    <span class="k">return</span> <span class="mi">4</span><span class="o">*</span><span class="p">(</span><span class="mi">3</span><span class="o">*</span><span class="n">arctan</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="n">one</span><span class="p">)</span> <span class="o">+</span> <span class="n">arctan</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">one</span><span class="p">)</span> <span class="o">+</span> <span class="n">arctan</span><span class="p">(</span><span class="mi">1985</span><span class="p">,</span> <span class="n">one</span><span class="p">))</span>

<span class="k">def</span> <span class="nf">pi_hutton</span><span class="p">(</span><span class="n">one</span><span class="p">):</span>
    <span class="k">return</span> <span class="mi">4</span><span class="o">*</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">arctan</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">one</span><span class="p">)</span> <span class="o">+</span> <span class="n">arctan</span><span class="p">(</span><span class="mi">7</span><span class="p">,</span> <span class="n">one</span><span class="p">))</span>

<span class="k">def</span> <span class="nf">pi_gauss</span><span class="p">(</span><span class="n">one</span><span class="p">):</span>
    <span class="k">return</span> <span class="mi">4</span><span class="o">*</span><span class="p">(</span><span class="mi">12</span><span class="o">*</span><span class="n">arctan</span><span class="p">(</span><span class="mi">18</span><span class="p">,</span> <span class="n">one</span><span class="p">)</span> <span class="o">+</span> <span class="mi">8</span><span class="o">*</span><span class="n">arctan</span><span class="p">(</span><span class="mi">57</span><span class="p">,</span> <span class="n">one</span><span class="p">)</span> <span class="o">-</span> <span class="mi">5</span><span class="o">*</span><span class="n">arctan</span><span class="p">(</span><span class="mi">239</span><span class="p">,</span> <span class="n">one</span><span class="p">))</span>
</pre></div>


</div>
<p>It turns out that Machin's formula is really very good, but Gauss's formula is slightly better.</p>
<p>The other way we can do better is to use a better formula for <tt class="docutils literal">arctan()</tt>.  <a class="reference external" href="http://en.wikipedia.org/wiki/Leonhard_Euler">Euler</a> came up with this <a class="reference external" href="http://mathworld.wolfram.com/InverseTangent.html">accelerated formula for arctan</a>:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/180899b6c341c96a41270221b9c97621.png" alt="\[
arctan(1/x) = \frac{x}{1+x^2}
            + \frac{2}{3}\frac{x}{(1+x^2)^2}
            + \frac{2\cdot4}{3\cdot5}\frac{x}{(1+x^2)^3}
            + \frac{2\cdot4\cdot6}{3\cdot5\cdot7}\frac{x}{(1+x^2)^4}
            + \cdots
\]
" title="\[
arctan(1/x) = \frac{x}{1+x^2}
            + \frac{2}{3}\frac{x}{(1+x^2)^2}
            + \frac{2\cdot4}{3\cdot5}\frac{x}{(1+x^2)^3}
            + \frac{2\cdot4\cdot6}{3\cdot5\cdot7}\frac{x}{(1+x^2)^4}
            + \cdots
\]
" /></div>
<p>This converges to <tt class="docutils literal">arctan(1/x)</tt> at the roughly the same rate per term than the formula above, however each term is made directly from the previous term by multiplying by <tt class="docutils literal">2n</tt> and dividing by <tt class="docutils literal"><span class="pre">(2n+1)(1+x²)</span></tt>.  This means that it can be implemented with only one (instead of two) divisions per term, and hence runs roughly twice as quickly.  If we implement this in python in fixed point, then it looks like this:</p>
<div class="literal-block">

<div class="pygments_murphy"><pre><span class="k">def</span> <span class="nf">arctan_euler</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">one</span><span class="o">=</span><span class="mi">1000000</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Calculate arctan(1/x) using euler&#39;s accelerated formula</span>

<span class="sd">    This calculates it in fixed point, using the value for one passed in</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">x_squared</span> <span class="o">=</span> <span class="n">x</span> <span class="o">*</span> <span class="n">x</span>
    <span class="n">x_squared_plus_1</span> <span class="o">=</span> <span class="n">x_squared</span> <span class="o">+</span> <span class="mi">1</span>
    <span class="n">term</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span> <span class="o">*</span> <span class="n">one</span><span class="p">)</span> <span class="o">//</span> <span class="n">x_squared_plus_1</span>
    <span class="n">total</span> <span class="o">=</span> <span class="n">term</span>
    <span class="n">two_n</span> <span class="o">=</span> <span class="mi">2</span>
    <span class="k">while</span> <span class="mi">1</span><span class="p">:</span>
        <span class="n">divisor</span> <span class="o">=</span> <span class="p">(</span><span class="n">two_n</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="n">x_squared_plus_1</span>
        <span class="n">term</span> <span class="o">*=</span> <span class="n">two_n</span>
        <span class="n">term</span> <span class="o">=</span> <span class="n">term</span> <span class="o">//</span> <span class="n">divisor</span>
        <span class="k">if</span> <span class="n">term</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">break</span>
        <span class="n">total</span> <span class="o">+=</span> <span class="n">term</span>
        <span class="n">two_n</span> <span class="o">+=</span> <span class="mi">2</span>
    <span class="k">return</span> <span class="n">total</span>
</pre></div>


</div>
<p>Notice how we pre-calculate as many things as possible (like <tt class="docutils literal">x_squared_plus_1</tt>) to get them out of the loop.</p>
<p>See the complete program: <a class="reference external" href="/nick/pub/pymath/pi_arctan_integer.py">pi_artcan_integer.py</a>.  Here are some timings <a class="footnote-reference" href="#id6" id="id3">[3]</a> of how the Machin and the Gauss arctan formula fared, with and without the accelerated arctan.</p>
<table border="1" class="docutils">
<colgroup>
<col width="18%" />
<col width="18%" />
<col width="33%" />
<col width="31%" />
</colgroup>
<thead valign="bottom">
<tr><th class="head">Formula</th>
<th class="head">Digits</th>
<th class="head">Normal Arctan
(seconds)</th>
<th class="head">Euler Arctan
(seconds)</th>
</tr>
</thead>
<tbody valign="top">
<tr><td>Machin</td>
<td>10</td>
<td>3.004e-05</td>
<td>2.098e-05</td>
</tr>
<tr><td>Gauss</td>
<td>10</td>
<td>2.098e-05</td>
<td>1.907e-05</td>
</tr>
<tr><td>Machin</td>
<td>100</td>
<td>0.0001869</td>
<td>0.0001471</td>
</tr>
<tr><td>Gauss</td>
<td>100</td>
<td>0.0001869</td>
<td>0.0001468</td>
</tr>
<tr><td>Machin</td>
<td>1000</td>
<td>0.005599</td>
<td>0.003520</td>
</tr>
<tr><td>Gauss</td>
<td>1000</td>
<td>0.005398</td>
<td>0.003445</td>
</tr>
<tr><td>Machin</td>
<td>10000</td>
<td>0.3995</td>
<td>0.2252</td>
</tr>
<tr><td>Gauss</td>
<td>10000</td>
<td>0.3908</td>
<td>0.2186</td>
</tr>
<tr><td>Machin</td>
<td>100000</td>
<td>38.33</td>
<td>21.69</td>
</tr>
<tr><td>Gauss</td>
<td>100000</td>
<td>37.44</td>
<td>21.12</td>
</tr>
<tr><td>Machin</td>
<td>1000000</td>
<td>3954.1</td>
<td>2396.8</td>
</tr>
<tr><td>Gauss</td>
<td>1000000</td>
<td>3879.4</td>
<td>2402.1</td>
</tr>
</tbody>
</table>
<p>There are several interesting things to note.  Firstly that we just calculated 1,000,000 decimal places of π in 40 minutes! Secondly that to calculate 10 times as many digits it takes 100 times as long.  This means that our algorithm scales as O(n²) where n is the number of digits.  So if 1,000,000 digits takes an hour, 10,000,000 would take 100 hours (4 days) and 100,000,000 would take 400 days (13 months).  Your computer might run out of memory, or explode in some other fashion when calculating 100,000,000 digits, but doesn't seem impossible any more.</p>
<p>The Gauss formula is slightly faster than the Machin for nearly all the results.  The accelerated arctan formula is 1.6 times faster than the normal arctan formula so that is a definite win.</p>
<p>A billion (1,000,000,000) digits of pi would take about 76 years to calculate using this program which is a bit out of our reach!  There are several ways we could improve this.  If we could find an algorithm for calculating π which was quicker than O(n²), or if we could find an O(n²) algorithm which just ran a lot faster.  We could also throw more CPUs at the problem.  To see how this might be done, we could calculate all the odd terms on one processor, and all the even terms on another processor for the <tt class="docutils literal">arctan</tt> formula and add them together at the end..  That would run just about twice as quickly.  That could easily be generalised to lots of processors:</p>
<pre class="literal-block">
arctan(1/x) = 1/x - 1/3x³ + 1/5x⁵ - 1/7x⁷ + ...
            = 1/x         + 1/5x⁵ -       + ... # run on cpu 1
            +     - 1/3x³         - 1/7x⁷ + ... # run on cpu 2
</pre>
<p>So if we had 76 CPU cores, we could probably calculate π to 1,000,000,000 places in about a year.</p>
<p>There are better algorithms for calculating π though, and there are faster ways of doing arithmetic than python's built in long integers.  We'll explore both in <a class="reference external" href="/nick/articles/pi-chudnovsky/">Part 4</a>!</p>
<table class="docutils footnote" frame="void" id="id4" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id1">[1]</a></td><td>Python's integer type was called called <tt class="docutils literal">long</tt> in python 2, just <tt class="docutils literal">int</tt> in python 3</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="id5" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id2">[2]</a></td><td>Unless you are using python 2</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="id6" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id3">[3]</a></td><td>All timings generated on my 2010 Intel® Core™ i7 CPU Q820 &#64; 1.73GHz running 64 bit Linux</td></tr>
</tbody>
</table>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Pi - Archimedes</title>
      <link>http://www.craig-wood.com/nick/articles/pi-archimedes</link>
      <pubDate>Mon, 18 Jul 2011 00:00:00 BST</pubDate>
      <category><![CDATA[maths]]></category>
      <category><![CDATA[pymath]]></category>
      <category><![CDATA[python]]></category>
      <guid>http://www.craig-wood.com/nick/articles/pi-archimedes</guid>
      <description>Pi - Archimedes</description>
      <content:encoded><![CDATA[<div class="document">
<p>It is clear from <a class="reference external" href="/nick/articles/pi-gregorys-series/">Part 1</a> that in order to calculate π we are going to need a better method than evaluating <a class="reference external" href="http://mathworld.wolfram.com/GregorySeries.html">Gregory's Series</a>.</p>
<div class="sidebar">
<p class="first sidebar-title">Fun with Maths and Python</p>
<p class="last">This is a having fun with maths and python article.  See <a class="reference external" href="/nick/articles/fun-with-maths-and-python-introduction/">the introduction</a> for important information!</p>
</div>
<p>Here is one which was originally discovered by Archimedes in 200BC.  Most of the proofs for series for calculating π require calculus or other advanced math, but since Archimedes didn't know any of those you can prove it without!  In fact I thought I had discovered it for the first time when I was 13 or so, but alas I was 2000 years too late!</p>
<p>Archimedes knew that the ratio of the circumference of a circle to its diameter was π.  He had the idea that he could draw a regular polygon inscribed within the circle to approximate π, and the more sides he drew on the polygon, the better approximation to π he would get.  In modern maths speak, we would say as the number of sides of the polygon tends to infinity, the circumference tends to 2π.</p>
<p>Instead of drawing the polygon though, Archimedes calculated the length using a geometric argument, like this.</p>
<img alt="Diagram for proof of Archimedes π formula" src="/nick/pub/pymath/pi_geometric_proof.png" />
<p>Draw a circle of radius 1 unit centered at A.  Inscribe an N sided polygon within it.  Our estimate for π is half the circumference of the polygon (circumference of a circle is 2πr, r = 1, giving 2π).  As the sides of the polygon get smaller and smaller the circumference gets closer and closer to 2π.</p>
<p>The diagram shows one segment of the polygon ACE.  The side of the polygon CE has length d <sub>n</sub>.  Assuming we know d for an N sided polygon,  If we can find an expression for the length CD = d <sub>2n</sub>, the edge length of a polygon with 2N sides, in terms of d <sub>n</sub> only, then we can improve our estimate for π.  Let's try to do that.</p>
<p>We bisect the triangle CAE to make CAD and DAE the two new equal segments of the 2N sided polygon.</p>
<p>Using Pythagoras's theorem on the right angled triangle ABC, we can see:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/02c4bc788092ae34ca32cc792d1f5d6e.png" alt="\begin{eqnarray*}
AB^2 + BC^2 &amp;=&amp; 1^2 = 1 \\
         AB &amp;=&amp; \sqrt{1 - BC^2} \\
\end{eqnarray*}
" title="\begin{eqnarray*}
AB^2 + BC^2 &amp;=&amp; 1^2 = 1 \\
         AB &amp;=&amp; \sqrt{1 - BC^2} \\
\end{eqnarray*}
" /></div>
<p>Given that</p>
<div class="literal-block"><img class="math" src="/nick/images/math/82da3bdf62deceff8e318fc67de00c47.png" alt="\begin{equation*}
   BC = \frac{d_n}{2}
\end{equation*}
" title="\begin{equation*}
   BC = \frac{d_n}{2}
\end{equation*}
" /></div>
<p>Substituting gives</p>
<div class="literal-block"><img class="math" src="/nick/images/math/27ed5b85afe73099185db2d8d9f22139.png" alt="\begin{eqnarray*}
   AB &amp;=&amp; \sqrt{1-\left(\frac{d_n}{2}\right)^2} \\
   BD &amp;=&amp; 1 - AB \\
      &amp;=&amp; 1 - \sqrt{1-\frac{d_n^2}{4}} \\
\end{eqnarray*}
" title="\begin{eqnarray*}
   AB &amp;=&amp; \sqrt{1-\left(\frac{d_n}{2}\right)^2} \\
   BD &amp;=&amp; 1 - AB \\
      &amp;=&amp; 1 - \sqrt{1-\frac{d_n^2}{4}} \\
\end{eqnarray*}
" /></div>
<p>Using Pythagoras's theorem on the right angled triangle CBD</p>
<div class="literal-block"><img class="math" src="/nick/images/math/4c9a9216949a8404fda6f2ef74d944f8.png" alt="\begin{eqnarray*}
CD^2 &amp;=&amp; BC^2 + BD^2 \\
    &amp;=&amp; \left(\frac{d_n}{2}\right)^2 + \left(1 - \sqrt{1-\left(\frac{d_n}{2}\right)^2}\right)^2 \\
    &amp;=&amp; \frac{d_n^2}{4} + \left(1 - 2\sqrt{1-\frac{d_n^2}{4}} + \left(1 - \frac{d_n^2}{4}\right)\right) \\
    &amp;=&amp; 2 - 2\sqrt{1-\frac{d_n^2}{4}} \\
CD = d_{2n} &amp;=&amp; \sqrt{2 - 2\sqrt{1-\frac{d_n^2}{4}}} \\
\end{eqnarray*}
" title="\begin{eqnarray*}
CD^2 &amp;=&amp; BC^2 + BD^2 \\
    &amp;=&amp; \left(\frac{d_n}{2}\right)^2 + \left(1 - \sqrt{1-\left(\frac{d_n}{2}\right)^2}\right)^2 \\
    &amp;=&amp; \frac{d_n^2}{4} + \left(1 - 2\sqrt{1-\frac{d_n^2}{4}} + \left(1 - \frac{d_n^2}{4}\right)\right) \\
    &amp;=&amp; 2 - 2\sqrt{1-\frac{d_n^2}{4}} \\
CD = d_{2n} &amp;=&amp; \sqrt{2 - 2\sqrt{1-\frac{d_n^2}{4}}} \\
\end{eqnarray*}
" /></div>
<p>d <sub>2n</sub> is the length of one side of the polygon with 2N sides.</p>
<p>This means that if we know the length of the sides of a polygon with N sides, then we can calculate the length of the sides of a polygon with 2N sides.</p>
<p>What does this mean? Lets start with a square.  Inscribing a square in a circle looks like this, with the side length √2.  This gives an estimate for π as 2√2, which is poor (at 2.828) but it is only the start of the process.</p>
<img alt="Square inscribed in a circle" src="/nick/pub/pymath/pi_geometric_inscribed_square.png" />
<p>We can the calculate the side length of an octagon, from the side length of a square, and the side length of a 16-gon from an octagon etc.</p>
<img alt="Polygons inscribed in a circle" src="/nick/pub/pymath/pi_geometric_inscribed_polygons.png" />
<p>It's almost time to break out python, but before we do so, we'll just note that to calculate d <sub>2n</sub> from d <sub>n</sub>, the first thing you do is calculate d² and at the very end you take the square root.  This kind of suggests that it would be better to keep track of d² rather than d, which we do in the program below (<a class="reference external" href="/nick/pub/pymath/pi_archimedes.py">pi_archimedes.py</a>):</p>
<div class="literal-block">

<div class="pygments_murphy"><pre><span class="kn">import</span> <span class="nn">math</span>

<span class="k">def</span> <span class="nf">pi_archimedes</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Calculate n iterations of Archimedes PI recurrence relation</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">polygon_edge_length_squared</span> <span class="o">=</span> <span class="mf">2.0</span>
    <span class="n">polygon_sides</span> <span class="o">=</span> <span class="mi">4</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
        <span class="n">polygon_edge_length_squared</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="mi">1</span> <span class="o">-</span> <span class="n">polygon_edge_length_squared</span> <span class="o">/</span> <span class="mi">4</span><span class="p">)</span>
        <span class="n">polygon_sides</span> <span class="o">*=</span> <span class="mi">2</span>
    <span class="k">return</span> <span class="n">polygon_sides</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">polygon_edge_length_squared</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Try the series</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">16</span><span class="p">):</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">pi_archimedes</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
        <span class="n">error</span> <span class="o">=</span> <span class="n">result</span> <span class="o">-</span> <span class="n">math</span><span class="o">.</span><span class="n">pi</span>
        <span class="k">print</span><span class="p">(</span><span class="s">&quot;</span><span class="si">%8d</span><span class="s"> iterations </span><span class="si">%.10f</span><span class="s"> error </span><span class="si">%.10f</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">result</span><span class="p">,</span> <span class="n">error</span><span class="p">))</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
    <span class="n">main</span><span class="p">()</span>
</pre></div>


</div>
<p>If you run this, then it produces:</p>
<table border="1" class="docutils">
<colgroup>
<col width="24%" />
<col width="15%" />
<col width="29%" />
<col width="32%" />
</colgroup>
<thead valign="bottom">
<tr><th class="head">Iterations</th>
<th class="head">Sides</th>
<th class="head">Result</th>
<th class="head">Error</th>
</tr>
</thead>
<tbody valign="top">
<tr><td>0</td>
<td>4</td>
<td>2.8284271247</td>
<td>-0.3131655288</td>
</tr>
<tr><td>1</td>
<td>8</td>
<td>3.0614674589</td>
<td>-0.0801251947</td>
</tr>
<tr><td>2</td>
<td>16</td>
<td>3.1214451523</td>
<td>-0.0201475013</td>
</tr>
<tr><td>3</td>
<td>32</td>
<td>3.1365484905</td>
<td>-0.0050441630</td>
</tr>
<tr><td>4</td>
<td>64</td>
<td>3.1403311570</td>
<td>-0.0012614966</td>
</tr>
<tr><td>5</td>
<td>128</td>
<td>3.1412772509</td>
<td>-0.0003154027</td>
</tr>
<tr><td>6</td>
<td>256</td>
<td>3.1415138011</td>
<td>-0.0000788524</td>
</tr>
<tr><td>7</td>
<td>512</td>
<td>3.1415729404</td>
<td>-0.0000197132</td>
</tr>
<tr><td>8</td>
<td>1024</td>
<td>3.1415877253</td>
<td>-0.0000049283</td>
</tr>
<tr><td>9</td>
<td>2048</td>
<td>3.1415914215</td>
<td>-0.0000012321</td>
</tr>
<tr><td>10</td>
<td>4096</td>
<td>3.1415923456</td>
<td>-0.0000003080</td>
</tr>
<tr><td>11</td>
<td>8192</td>
<td>3.1415925765</td>
<td>-0.0000000770</td>
</tr>
<tr><td>12</td>
<td>16384</td>
<td>3.1415926335</td>
<td>-0.0000000201</td>
</tr>
<tr><td>13</td>
<td>32768</td>
<td>3.1415926548</td>
<td>0.0000000012</td>
</tr>
<tr><td>14</td>
<td>65536</td>
<td>3.1415926453</td>
<td>-0.0000000083</td>
</tr>
<tr><td>15</td>
<td>131072</td>
<td>3.1415926074</td>
<td>-0.0000000462</td>
</tr>
</tbody>
</table>
<p>Hooray!  We calculated π to 8 decimal places in only 13 iterations.  Iteration 0 for the square shows up the expected 2.828 estimate for π. You can see after iteration 13 that the estimate of π starts getting worse.  That is because we only calculated all our calculations to the limit of precision of python's <a class="reference external" href="http://docs.python.org/tutorial/floatingpoint.html">floating point numbers</a> (about 17 digits), and all those errors start adding up.</p>
<p>We can easily calculate more digits of π using Pythons excellent <a class="reference external" href="http://docs.python.org/library/decimal.html">decimal module</a>.  This allows you to do arbitrary precision arithmetic on numbers.  It isn't particularly quick, but it is built in and easy to use.</p>
<p>Let's calculate π to 100 decimal places now.  That sounds like a significant milestone! (<a class="reference external" href="/nick/pub/pymath/pi_archimedes_decimal.py">pi_archimedes_decimal.py</a>):</p>
<div class="literal-block">

<div class="pygments_murphy"><pre><span class="kn">from</span> <span class="nn">decimal</span> <span class="kn">import</span> <span class="n">Decimal</span><span class="p">,</span> <span class="n">getcontext</span>

<span class="k">def</span> <span class="nf">pi_archimedes</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Calculate n iterations of Archimedes PI recurrence relation</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">polygon_edge_length_squared</span> <span class="o">=</span> <span class="n">Decimal</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
    <span class="n">polygon_sides</span> <span class="o">=</span> <span class="mi">2</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
        <span class="n">polygon_edge_length_squared</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">-</span> <span class="n">polygon_edge_length_squared</span> <span class="o">/</span> <span class="mi">4</span><span class="p">)</span><span class="o">.</span><span class="n">sqrt</span><span class="p">()</span>
        <span class="n">polygon_sides</span> <span class="o">*=</span> <span class="mi">2</span>
    <span class="k">return</span> <span class="n">polygon_sides</span> <span class="o">*</span> <span class="n">polygon_edge_length_squared</span><span class="o">.</span><span class="n">sqrt</span><span class="p">()</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Try the series</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">places</span> <span class="o">=</span> <span class="mi">100</span>
    <span class="n">old_result</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="o">*</span><span class="n">places</span><span class="p">):</span>
        <span class="c"># Do calculations with double precision</span>
        <span class="n">getcontext</span><span class="p">()</span><span class="o">.</span><span class="n">prec</span> <span class="o">=</span> <span class="mi">2</span><span class="o">*</span><span class="n">places</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">pi_archimedes</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
        <span class="c"># Print the result with single precision</span>
        <span class="n">getcontext</span><span class="p">()</span><span class="o">.</span><span class="n">prec</span> <span class="o">=</span> <span class="n">places</span>
        <span class="n">result</span> <span class="o">=</span> <span class="o">+</span><span class="n">result</span>           <span class="c"># do the rounding on result</span>
        <span class="k">print</span><span class="p">(</span><span class="s">&quot;</span><span class="si">%3d</span><span class="s">: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">result</span><span class="p">))</span>
        <span class="k">if</span> <span class="n">result</span> <span class="o">==</span> <span class="n">old_result</span><span class="p">:</span>
            <span class="k">break</span>
        <span class="n">old_result</span> <span class="o">=</span> <span class="n">result</span>
</pre></div>


</div>
<p>You'll see if you look at the <tt class="docutils literal">pi_archimedes</tt> function that not a lot has changed.  Instead of using the <tt class="docutils literal">math.sqrt</tt> function we use the <tt class="docutils literal">sqrt</tt> method of the <tt class="docutils literal">Decimal</tt> object.  The edge gets initialised to <tt class="docutils literal">Decimal(2)</tt> rather than <tt class="docutils literal">2.0</tt> but otherwise the methods are the same.  The <tt class="docutils literal">main</tt> method has changed a bit.  You'll see that we set the precision of the decimal calculations using the <tt class="docutils literal"><span class="pre">getcontext().prec</span> = ...</tt> call.  This sets the precision for all following calculations.  There are other ways to do this which you can see in the <a class="reference external" href="http://docs.python.org/library/decimal.html">decimal module</a> docs.  We do the Archimedes calculations with 200 decimal places precision, then print the result out with 100 decimal places precision by changing the precision and using the <tt class="docutils literal">result = +result</tt> trick.  When the result stops changing we end, because that must be π!</p>
<p>If you run this, you'll find at iteration 168 it produces 100 accurately rounded decimal places of π.  So far so good!</p>
<p>There are two downsides to this function though.  One is that the decimal arithmetic is quite slow.  On my computer it takes about 6 seconds to calculate 100 digits of π which sounds fast, but if you were to try for 1,000,000 places you would be waiting a very very long time!  The other problem is the square root.  Square roots are expensive operations, they take lots of multiplications and divisions and we need to do away with that to go faster.</p>
<p>In <a class="reference external" href="/nick/articles/pi-machin/">Part 3</a> we'll be getting back to the infinite series for <tt class="docutils literal">arctan</tt> and on to much larger numbers of digits of π.</p>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Pi - Gregory's Series</title>
      <link>http://www.craig-wood.com/nick/articles/pi-gregorys-series</link>
      <pubDate>Sun, 17 Jul 2011 00:00:00 BST</pubDate>
      <category><![CDATA[maths]]></category>
      <category><![CDATA[pymath]]></category>
      <category><![CDATA[python]]></category>
      <guid>http://www.craig-wood.com/nick/articles/pi-gregorys-series</guid>
      <description>Pi - Gregory's Series</description>
      <content:encoded><![CDATA[<div class="document">
<p>Lets calculate π (or Pi if you prefer)!  π is an irrational number (amongst other things) which means that it isn't one whole number divided by another whole number.  In fact the digits of π are extremely random - if you didn't know they were the digits of π they would be perfectly random.</p>
<div class="sidebar">
<p class="first sidebar-title">Fun with Maths and Python</p>
<p class="last">This is a having fun with maths and python article.  See <a class="reference external" href="/nick/articles/fun-with-maths-and-python-introduction/">the introduction</a> for important information!</p>
</div>
<p>π has been calculated to billions of decimal places, but in this series of articles, we're going to aim for the more modest target of 100,000,000 decimal places calculated by a python program in a reasonable length of time.  We are going to try some different formulae and algorithms following a roughly historical path.</p>
<p>You were probably taught at school that 22/7 is a reasonable approximation to π.  Maybe you were even taught that 355/113 was a better one.  You were unlikely to have been taught how π is actually calculated.  You could draw a circle and measure the circumference, but that is very hard to do accurately.</p>
<p>Luckily maths comes to the rescue.  There are 100s of formulae for calculating π, but the simplest one I know of is this:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/d3126204bac6d03431b3b0903f0dbf13.png" alt="\begin{equation*}
\frac{\pi}{4} = 1 - \frac{1}{3} + \frac{1}{5} - \frac{1}{7} + \frac{1}{9} - \frac{1}{11} + \frac{1}{13} - \frac{1}{15} + \frac{1}{17} - \cdots
\end{equation*}
" title="\begin{equation*}
\frac{\pi}{4} = 1 - \frac{1}{3} + \frac{1}{5} - \frac{1}{7} + \frac{1}{9} - \frac{1}{11} + \frac{1}{13} - \frac{1}{15} + \frac{1}{17} - \cdots
\end{equation*}
" /></div>
<p>This is known as <a class="reference external" href="http://mathworld.wolfram.com/GregorySeries.html">Gregory's Series</a>  (or sometimes the Leibnitz formula) for π.  That <tt class="docutils literal">...</tt> stands for keep going forever.  To make the next term in the series, alternate the sign, and add 2 to the denominator of the fraction, so <tt class="docutils literal">+ 1/19</tt> is next then <tt class="docutils literal">- 1/21</tt> etc.</p>
<p>To see why this is true, we need to look at the <a class="reference external" href="http://mathworld.wolfram.com/LeibnizSeries.html">Leibnitz</a> formula for <tt class="docutils literal">arctan</tt> (or <tt class="docutils literal">tan⁻¹</tt>).  This is:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/5504b0bdb260f89a3319d6892f59c0cb.png" alt="\begin{equation*}
arctan(x) = x - \frac{x^3}{3} + \frac{x^5}{5} - \frac{x^7}{7} + \frac{x^9}{9} - \cdots ( -1 &lt;= x &lt;= 1 )
\end{equation*}
" title="\begin{equation*}
arctan(x) = x - \frac{x^3}{3} + \frac{x^5}{5} - \frac{x^7}{7} + \frac{x^9}{9} - \cdots ( -1 &lt;= x &lt;= 1 )
\end{equation*}
" /></div>
<p>Note that the result of <tt class="docutils literal">arctan(x)</tt> is in radians. I'm not going to prove that formula here as it involves calculus, but you can see <a class="reference external" href="http://www.math.wpi.edu/IQP/BVCalcHist/calc3.html">a proof of the arctan formula</a> if you want.</p>
<p><tt class="docutils literal">arctan</tt> is the inverse of <tt class="docutils literal">tan</tt>, so <tt class="docutils literal">arctan(tan(x)) = x</tt>.  <tt class="docutils literal">tan(x)</tt> is the familiar (hopefully) ratio of the opposite and adjacent sides of a right angled triangle and how that relates to the angle.</p>
<p>If we set the angle to 45°, which is π/4 radians, then:</p>
<pre class="literal-block">
   tan(45°) = 1
⇒ tan(π/4) = 1
⇒ arctan(1) = π/4
</pre>
<p>which when substituted in the above becomes:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/bae97565c0ef3f8dce33fd50e10c5270.png" alt="\begin{equation*}
\frac{\pi}{4} = 1 - \frac{1}{3} + \frac{1}{5} - \frac{1}{7} + \frac{1}{9} - \cdots
\end{equation*}
" title="\begin{equation*}
\frac{\pi}{4} = 1 - \frac{1}{3} + \frac{1}{5} - \frac{1}{7} + \frac{1}{9} - \cdots
\end{equation*}
" /></div>
<p>This may be the simplest infinite series formula for π but it has the disadvantage that you'll need to add up a great number of terms to get an acceptably accurate answer.</p>
<p>Here is a bit of python to calculate it (<a class="reference external" href="/nick/pub/pymath/pi_gregory.py">pi_gregory.py</a>):</p>
<div class="literal-block">

<div class="pygments_murphy"><pre><span class="kn">import</span> <span class="nn">math</span>

<span class="k">def</span> <span class="nf">pi_gregory</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Calculate n iterations of Gregory&#39;s series</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">result</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="n">divisor</span> <span class="o">=</span> <span class="mi">1</span>
    <span class="n">sign</span> <span class="o">=</span> <span class="mi">1</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
        <span class="n">result</span> <span class="o">+=</span> <span class="n">sign</span> <span class="o">/</span> <span class="n">divisor</span>
        <span class="n">divisor</span> <span class="o">+=</span> <span class="mi">2</span>
        <span class="n">sign</span> <span class="o">=</span> <span class="o">-</span><span class="n">sign</span>
    <span class="k">return</span> <span class="mi">4</span> <span class="o">*</span> <span class="n">result</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Try Gregory&#39;s series</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">for</span> <span class="n">log_n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">8</span><span class="p">):</span>
        <span class="n">n</span> <span class="o">=</span> <span class="mi">10</span><span class="o">**</span><span class="n">log_n</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">pi_gregory</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
        <span class="n">error</span> <span class="o">=</span> <span class="n">result</span> <span class="o">-</span> <span class="n">math</span><span class="o">.</span><span class="n">pi</span>
        <span class="k">print</span><span class="p">(</span><span class="s">&quot;</span><span class="si">%8d</span><span class="s"> iterations </span><span class="si">%.10f</span><span class="s"> error </span><span class="si">%.10f</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">result</span><span class="p">,</span> <span class="n">error</span><span class="p">))</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
    <span class="n">main</span><span class="p">()</span>
</pre></div>


</div>
<p>All the important stuff happens in <tt class="docutils literal">pi_gregory</tt> and hopefully you'll see how that relates to the infinite series for <tt class="docutils literal">arctan</tt>.  Note the trick of keeping the sign of the term in a variable as <tt class="docutils literal">1</tt> or <tt class="docutils literal"><span class="pre">-1</span></tt> and then multiplying by this.  This is a common trick, easier to write than an if statement and probably faster.</p>
<p>The program above prints:</p>
<table border="1" class="docutils">
<colgroup>
<col width="29%" />
<col width="34%" />
<col width="37%" />
</colgroup>
<thead valign="bottom">
<tr><th class="head">Iterations</th>
<th class="head">Result</th>
<th class="head">Error</th>
</tr>
</thead>
<tbody valign="top">
<tr><td>10</td>
<td>3.0418396189</td>
<td>-0.0997530347</td>
</tr>
<tr><td>100</td>
<td>3.1315929036</td>
<td>-0.0099997500</td>
</tr>
<tr><td>1000</td>
<td>3.1405926538</td>
<td>-0.0009999997</td>
</tr>
<tr><td>10000</td>
<td>3.1414926536</td>
<td>-0.0001000000</td>
</tr>
<tr><td>100000</td>
<td>3.1415826536</td>
<td>-0.0000100000</td>
</tr>
<tr><td>1000000</td>
<td>3.1415916536</td>
<td>-0.0000010000</td>
</tr>
<tr><td>10000000</td>
<td>3.1415925536</td>
<td>-0.0000001000</td>
</tr>
</tbody>
</table>
<p>That looks like our old friend π doesn't it!  However you can see that it takes 10 times as many iterations to add another decimal place of accuracy to the result.  That isn't going to get us even 10 decimal places in a reasonable length of time... We'll have to get a bit cleverer. (If the program printed out something very different then you need to run it with python 3 not python 2 see <a class="reference external" href="/nick/articles/fun-with-maths-and-python-introduction/">the introduction</a>.)  You can also see something very odd in the error terms - the result is correct to 10 decimal places, all except for one digit.  This is a known oddity and you can read up about it <a class="reference external" href="http://en.wikipedia.org/wiki/Leibniz_formula_for_pi">The Leibniz formula for pi</a> .</p>
<p>Those of you paying attention will have noted that we used <tt class="docutils literal">math.pi</tt> from the python standard library in the above program to calculate the difference of the result from π.  So python already knows the value of π! However that is only a double precison value (17 digits or so) and we are aiming for much more.  We are going to leave the world of double precision floating point behind, and calculate a lot more digits of π, much quicker, in the next exciting episode (<a class="reference external" href="/nick/articles/pi-archimedes/">Part 2</a>)!</p>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Fun with Maths and Python - Introduction</title>
      <link>http://www.craig-wood.com/nick/articles/fun-with-maths-and-python-introduction</link>
      <pubDate>Sat, 16 Jul 2011 00:00:00 BST</pubDate>
      <category><![CDATA[pymath]]></category>
      <guid>http://www.craig-wood.com/nick/articles/fun-with-maths-and-python-introduction</guid>
      <description>Fun with Maths and Python - Introduction</description>
      <content:encoded><![CDATA[<div class="document">
<p>This is going to be a series of articles which are all about having fun with maths and <a class="reference external" href="http://www.python.org/">Python</a>.  I'm going to show you a bit of maths and then how to apply it with a python program, then work out how to improve it.</p>
<p>I decided to write these after looking in my doodles folder on my computer and finding 100s of programs to calculate this bit of maths, or explore that bit of maths, and I thought it would be interesting for me to share them.  Hopefully you'll find it interesting too!</p>
<p>I'm going to use python 3 for all python code.  This enables me to future proof these articles and encourage everyone who hasn't tried Python 3 to have a go.  The programs will run with minor modifications on python 2 - just watch out for <a class="reference external" href="http://www.python.org/dev/peps/pep-0238/">division which has changed from python 2 to 3</a>.  In fact if you run any of these programs under python 2 then put <tt class="docutils literal">from __future__ import division</tt> at the top of them.</p>
<p>Python is a really excellent language for investigations into maths.  It is easy to read and has excellent long number support with infinite precision integers and the <a class="reference external" href="http://docs.python.org/library/decimal.html">decimal module</a>.  I'm going to attempt to demonstrate what I want to demonstrate not using any third party modules, but I may occasionally use the <a class="reference external" href="https://code.google.com/p/gmpy/">gmpy module</a>.</p>
<p>I'm going to pitch the level of maths below calculus, no more than the maths that everyone should have learnt at school.  If I want to use some bit of maths outside that range I'll explain it first.  This does means that sometimes I won't be able to show a proof for things, but I'll add a link to an online proof if I can find one.</p>
<p>You are going to see maths written both in traditional style:</p>
<div class="literal-block"><img class="math" src="/nick/images/math/30d4bf5df78e59a457cf2f90ee9028c7.png" alt="\begin{equation*}
x=\frac{-b \pm \sqrt {b^2-4ac}}{2a}
\end{equation*}
" title="\begin{equation*}
x=\frac{-b \pm \sqrt {b^2-4ac}}{2a}
\end{equation*}
" /></div>
<p>And in computer style which every programmer knows anyway.  This involves a few more brackets, but it is much easier to translate to computer code.  For example:</p>
<pre class="literal-block">
(-b +/- sqrt(b**2 - 4*a*c)) / (2*a)
</pre>
<p>In Python computer maths we write:</p>
<blockquote>
<ul class="simple">
<li><tt class="docutils literal">*</tt> to mean multiply</li>
<li><tt class="docutils literal">/</tt> to mean divide</li>
<li><tt class="docutils literal">**</tt> to mean to the power</li>
<li><tt class="docutils literal">//</tt> to mean divide but give the result as an integer</li>
<li><tt class="docutils literal">%</tt> to mean the same as the <tt class="docutils literal">modulo</tt> or <tt class="docutils literal">mod</tt> operator, ie do the division and take the remainder.</li>
</ul>
</blockquote>
<p>I'm going to make free with unicode fonts so you'll see:</p>
<blockquote>
<ul class="simple">
<li>π - pi</li>
<li>x² - x squared</li>
<li>√x - square root of x</li>
<li>± - plus or minus</li>
</ul>
</blockquote>
<p>If these aren't appearing properly, then you'll need to try a different browser, or install some more fonts.</p>
<p>As for the programming level, anyone who knows a little bit of python should be able to work out what is happening - I won't be doing anything too fancy!</p>
<p>I'll tag all the articles with <a class="reference external" href="/nick/articles/category/pymath/">pymath</a> so you can find them or subscribe to the <a class="reference external" href="/nick/articles/category/pymath/feed">rss</a>.</p>
<p>Happy Calculating!</p>
<p>Nick Craig-Wood</p>
<p><a class="reference external" href="mailto:nick&#64;craig-wood.com">nick&#64;craig-wood.com</a></p>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Technology changes in 2010</title>
      <link>http://www.craig-wood.com/nick/articles/technology-changes-in-2010</link>
      <pubDate>Wed, 22 Dec 2010 14:56:39 GMT</pubDate>
      <category><![CDATA[tech]]></category>
      <guid>http://www.craig-wood.com/nick/articles/technology-changes-in-2010</guid>
      <description>Technology changes in 2010</description>
      <content:encoded><![CDATA[<div class="document">
<p>Technology that has come and gone from my life in 2010, and new stuff I've learnt.  More than I expected!</p>
<p>These notes are really for me to look back at over the years, but you might find them interesting.</p>
<div class="section" id="old">
<h1>Old</h1>
<p>Things gone from my life.  Gone but not forgotten :-</p>
<blockquote>
<ul class="simple">
<li><a class="reference external" href="http://www.mutt.org/">Mutt</a> - finally replaced with <a class="reference external" href="http://www.mozillamessaging.com/en-GB/thunderbird/">Thunderbird</a>.  Mutt is a terminal based email client, just in case you haven't heard of it.  It works really well for power users, is really configurable, but in these days of HTML emails and attachments it was no longer keeping up.  I loved him - he was a faithful mutt, but he had to go.  (Actually he is still there at the command line ready to go if needed - but keep it under your hat!)</li>
<li><a class="reference external" href="http://www.google.co.uk/images?q=courier+modem">Courier V34 modem</a> - years overdue, I finally disconnected it and consigned it to the pit of oblivion.  It used to receive faxes, but I don't think anyone has sent one for several years.  It also used to run a BBS and an Internet node, which was useful at times, but now GPRS/3G/Wifi is everywhere I want to go it is no longer needed.</li>
<li><a class="reference external" href="http://en.wikipedia.org/wiki/Integrated_Services_Digital_Network">ISDN</a> - 128k of digital goodness just wasn't good enough any more and became too expensive.  Great in its hey-day with 2 channels, 10 numbers and a whopping 64k digitial Internet connection.  Obsoleted by ADSL and <a class="reference external" href="http://www.gradwell.com/phoneservices/enterprise">VOIP</a>.</li>
<li><a class="reference external" href="http://www.nokia.co.uk/find-products/all-phones/nokia-e90-communicator">Nokia E90</a> &amp; <a class="reference external" href="http://en.wikipedia.org/wiki/Symbian_OS">Symbian</a> - sorry... we've had good times, but I've found someone else</li>
<li><a class="reference external" href="http://www.kde.org/">KDE</a> - you worked really well until version 4 where the bugs and the slowness really kicked in.</li>
<li><a class="reference external" href="http://en.wikimedia.org/wiki/Usenet">Usenet</a>  - This was my first hint of online communities on the Internet in 1994.  Unfortunately the cool kids have moved on, and so, reluctantly, have I!</li>
</ul>
</blockquote>
</div>
<div class="section" id="new">
<h1>New</h1>
<p>New technology :-</p>
<blockquote>
<ul class="simple">
<li><a class="reference external" href="http://www.mozillamessaging.com/en-GB/thunderbird/">Thunderbird</a> - for people with complicated email lives the plugin system makes life bearable!  Here are my top plugins<ul>
<li>Nostalgy - adds keyboard shortcuts to save, copy, goto folders</li>
<li>Quickfolders - Put your favourite folders along the top</li>
<li>Copy Sent to Current - copy sent mail to the current folder not the Sent folder - makes a new and better way of doing email</li>
<li>Display Mail User Agent - snoop on what other people use for their mail client</li>
<li>Enigmail - Use PGP to sign/encrypt your emails seamlessly</li>
<li>External Editor - edit emails in your favourite editor (eg emacs)</li>
<li>Identity Chooser - If you use multiple identities you need this!</li>
<li>Mail Redirect - proper bounce of email (not forward)</li>
</ul>
</li>
<li><a class="reference external" href="https://secure.wikimedia.org/wikipedia/en/wiki/UW_IMAP">IMAP</a> - makes it easy to migrate your email setup.  You can still use it with procmail so some things haven't changed ;-)  I can use it with my Android phone and the excellent <a class="reference external" href="https://code.google.com/p/k9mail/">K9Mail</a>.</li>
<li><a class="reference external" href="http://www.blogofile.com">Blogofile</a> - which makes this (fully static) website.  It replaces a pile of crufty hand built python scripts which did the same thing, just not nearly as well!</li>
<li><a class="reference external" href="http://www.ubuntu.com/">Ubuntu</a> on the desktop - I finally gave in and replaced <a class="reference external" href="http://http://www.debian.org/">Debian</a> testing with <a class="reference external" href="http://www.ubuntu.com/">Ubuntu</a> on my main laptop so I can spend less time fixing stuff and more time doing real work!  Debian still rules on the server though.</li>
<li><a class="reference external" href="http://www.gradwell.com/phoneservices/enterprise">VOIP</a> - I've signed up with a 100% Voip provider and migrated my 10 telephone numbers to them.  It went reasonably smoothly!  I took the ISDN card out of my Asterisk PBX.  We've been doing this at work for ages - it seemed like time to migrate at home too.</li>
<li><a class="reference external" href="http://www.android.org/">Android</a> - is Google's new phone operating system.  It runs on Linux and is mostly open source which are big positives in my view.  I've been enjoying my Android phone greatly and have written a number of applications - <a class="reference external" href="http://www.craig-wood.com/nick/android/oxo3d/">Oxo3d</a> is one.</li>
<li><a class="reference external" href="http://www.gnome.org/">Gnome</a> - well not new actually, I last gave Gnome up in about 2005 when I got irritated at no longer being able to edit my menus.  Unfortunately KDE 4 isn't shaping up for me, so it is hello again!</li>
</ul>
</blockquote>
</div>
<div class="section" id="books">
<h1>Books</h1>
<p>Tech books I've read this year.  No python books this year - I think I've read them all now!</p>
<blockquote>
<ul class="simple">
<li><a class="reference external" href="http://www.amazon.co.uk/dp/0596007736/?tag=niccrawoosweb-21">Java in a Nutshell</a> (again) programming to write Android programs.  I learnt original Java ages ago, but is is quite a different experience with generic types.  Still not my favourite language - reminds me too much of C++, but bearable.</li>
<li><a class="reference external" href="http://www.amazon.co.uk/dp/0981531601/?tag=niccrawoosweb-21">Programming In Scala</a> - just for fun - maybe I'll use it with Android one day.  Scala is one of the new breed of languages which runs on the Java VM.  Scala is a (mostly) functional language created by one of the creators of Java itself.</li>
<li><a class="reference external" href="http://www.amazon.co.uk/dp/0596520123/?tag=niccrawoosweb-21">Version Control with Git</a> - distributed revision control system.  Very clever idea with lots and lots of command lines to explore.  If it scales to the Linux kernel then surely it is good enough for my projects?</li>
<li><a class="reference external" href="http://www.amazon.co.uk/dp/0596002548/?tag=niccrawoosweb-21">BGP: Building Reliable Networks with the Border Gateway Protocol</a> - how the Internet really works!</li>
<li><a class="reference external" href="http://www.amazon.co.uk/dp/1933988673/?tag=niccrawoosweb-21">Unlocking Android: A Developer's Guide</a> - how to make Android applications</li>
<li><a class="reference external" href="http://www.amazon.co.uk/dp/1590595270/?tag=niccrawoosweb-21">Running IPv6</a> - yes it <em>is</em> coming - IPv4 addresses are running out very soon.</li>
</ul>
</blockquote>
<p>These are affiliate links, so if you click then buy I'll earn a few pence towards my next tech book!</p>
</div>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Oxo3d v0.94 released</title>
      <link>http://www.craig-wood.com/nick/articles/oxo3d-v0-94-released</link>
      <pubDate>Sun, 21 Nov 2010 18:48:00 GMT</pubDate>
      <category><![CDATA[oxo3d]]></category>
      <category><![CDATA[android]]></category>
      <guid>http://www.craig-wood.com/nick/articles/oxo3d-v0-94-released</guid>
      <description>Oxo3d v0.94 released</description>
      <content:encoded><![CDATA[<div class="document">
<p><a class="reference external" href="http://www.craig-wood.com/nick/android/oxo3d/">Oxo3d</a> v0.94 released.</p>
<p>Major changes are</p>
<blockquote>
<ul class="simple">
<li>Fix missing textures on milestone/droid</li>
</ul>
</blockquote>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Oxo3d v0.93 released</title>
      <link>http://www.craig-wood.com/nick/articles/oxo3d-v0-93-released</link>
      <pubDate>Sun, 21 Nov 2010 18:43:00 GMT</pubDate>
      <category><![CDATA[oxo3d]]></category>
      <category><![CDATA[android]]></category>
      <guid>http://www.craig-wood.com/nick/articles/oxo3d-v0-93-released</guid>
      <description>Oxo3d v0.93 released</description>
      <content:encoded><![CDATA[<div class="document">
<p><a class="reference external" href="http://www.craig-wood.com/nick/android/oxo3d/">Oxo3d</a> v0.93 released.</p>
<p>Major changes are</p>
<blockquote>
<ul class="simple">
<li>Fix keys / trackball not working sometimes</li>
<li>Fix back button</li>
<li>Update for new Market and new SDK</li>
<li>Make work properly on High/Low res devices</li>
</ul>
</blockquote>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Oxo3d v0.92 released</title>
      <link>http://www.craig-wood.com/nick/articles/oxo3d-v0-92-released</link>
      <pubDate>Wed, 28 Apr 2010 08:31:00 BST</pubDate>
      <category><![CDATA[oxo3d]]></category>
      <category><![CDATA[android]]></category>
      <guid>http://www.craig-wood.com/nick/articles/oxo3d-v0-92-released</guid>
      <description>Oxo3d v0.92 released</description>
      <content:encoded><![CDATA[<div class="document">
<p><a class="reference external" href="http://www.craig-wood.com/nick/android/oxo3d/">Oxo3d</a> v0.92 released.</p>
<p>Major changes are</p>
<blockquote>
<ul class="simple">
<li>Make the D-Pad rotate the view and the D-Pad center / search button flip view</li>
<li>Make the trackball work again</li>
<li>Fix 3D view bug</li>
<li>Fix 3D view disappearing after showing the help</li>
</ul>
</blockquote>
</div>
]]></content:encoded>
    </item>
  </channel>
</rss>

