CS 3723
  Programming Languages  
13. Arbitrary-Precision Float


Support for Arbitrary-Precision: Python lets ints be arbitrarily large (subject to available memory). Ordinary Python can't handle floating point numbers with more significant digits than a double (about 16), so if you want higher precision, you need some other software:

  • mpmath: a third-party addition to Python, this seems the best choice.

    • I installed it on my Linux system (using Python 2.6.5) at home with no trouble, downloading it from the link above and following directions at that link (to install you just run a Python program). The package works for Python 2.5 or higher, including Python 3.x. My install required root privileges, so I cannot install it on an elk, but I'll see if the systems people will do that.

    • I also installed it on a Mac computer, running OSX 10.6.8 (Leopard) with Python 2.6.1. This install was just as easy, again using root access. (Root access is disabled on Macs by default, but online Apple support tells how to enable it.)

    • It is also available for Windows, but I couldn't try that. (No Windows!)

    It is pure-Python code, and seems very sophisticated, with a lot of fancy capabilities and features. I'm just getting started on this (see below). See also mpmath docs. I tested both the Linux and the Mac OSX versions.

    Here is the tar file that contains the software: mpmath-0.19.tar. To extract the software, download and type: tar xf mpmath-0.19.tar

  • Others: Python has other such arbitrary-precision float libraries, as do C and Lisp and many others.


Sample Calculations: Here are computations of three formulas. The first is a famous weird formula that's very close to an integer:

mpmath: Sample Calculations
# mpmath_test.py
from mpmath import *
import sys

mp.dps = 50 # 50 digit calculations
print "Precision: ", mp.dps
print mpf(2)**mpf('0.5') # sqrt(2)
print 2*pi # 2*pi
near_int = e**(pi*mpf(163)**mpf('0.5'))
print near_int # very close to an int
% Python mpmath.py
Precision:  50
1.4142135623730950488016887242096980785696718753769
6.2831853071795864769252867665590057683943387987502
262537412640768743.99999999999925007259719818568887

         1         2         3         4         5
12345678901234567890123456789012345678901234567890

(all digits above are correct)

Next are two formulas giving π accurate to 30 and to 52 decimals.

mpmath: More Sample Calculations
# tmp.py
from mpmath import *
import sys

mp.dps = 80
print "Precision: ", mp.dps
pi_approx = mp.log(mpf(640320) ** 3 + mpf(744)) / mp.sqrt(163)
print pi_approx

pi_approx2 = mp.log( (mpf(5280) * (mpf(236674) + mpf(30303) * \
      mp.sqrt(mpf(61)))) ** 3 + mpf(744)) / mp.sqrt(mpf(427))
print pi_approx2
print pi

% Python tmp.py
Precision:  80
3.1415926535897932384626433832797266193475498808835224222929628774422587390510494
3.1415926535897932384626433832795028841971693993751058600689073618724169264129391
3.141592653589793238462643383279502884197169399375105820974944592307816406286209

           1         2         3         4         5         6         7         8
  12345678901234567890123456789012345678901234567890123456789012345678901234567890

Try this one:

Items of Interest or for study (see mpmath docs):

  • You can use import mpmath at the head, but then you need to add mpmath. at the start of the references to the library.

  • mp.dps=50 declares the precision to be 50 digits. You can change this precision any time in the program.

  • mpf(2) declares a high-precision constant with value 2. Notice from the mpmath docs that mpr(10.1) doesn't work correctly, while mpr('10.1') does.

  • The software works with ordinary arithmetic operators and with ordinary integer constants. (I've sometimes changed an integer constant to multi-precision form when it wasn't required.)

  • There are often alternatives to ordinary operators, as with:

    Instead of ... you can write:
    e ** (...)mp.exp(...)
    (...) ** mpf('0.5')mp.sqrt(...)

  • Determining error bounds is important and hard to do. I haven't been bothering with this, and I'm sticking to problems where I already know the correct answer.


Gregory's Series: Here we're showing a larger calculation: sums of Gregory's series, using the formula below. These sums are computed with up to 130-digit accuracy, using Python, with the mpmath extension. (I've carried out many of these calculations on Mathematica and clisp, getting exactly the same results.)

mpmath: More Sample Calculations
Ordinary Python Python with mpmath
# greg.py

import sys


N = 100000
sum = 0.0
sign = 1
for k in range(0,N):
    term = 1.0/(2.0*k + 1.0)
    sum = sum + sign*term
    if k%(N/50) == 0:
        sys.stdout.write(str(k) +
          " " + str(sum) + "\n")
    sign = -sign
sys.stdout.write(str(k) + " " +
  str(sum) + "\n")
sys.stdout.write(str(k) +
  " " + str(sum*4) + "\n")
# greg_mp.py: sum Gregory's series, multi-prec
from mpmath import *
import sys
mp.dps = 100
print "Precision: ", mp.dps
N = 10000000
sum = mpf(0)
sign = 1
for k in range(0,N):
    term = mpf(1)/(mpf(2)*k + (mpf(1)))
    sum = sum + sign*term
    if k%(N/50) == 0:
        sys.stdout.write(str(k) + " " +
          str(sum) + "\n")
    sign = -sign
sys.stdout.write(str(k) + " " +
  str(sum) + "\n")
sys.stdout.write(str(k) + " " +
  str(sum*4) + "\n")

Below, the blue digits are initial correct ones, the red digits are incorrect, and the green digits are correct digits that come after at least one incorrect one.

Calculate Pi, slow convergence, up to 150-digit accuracy.
N=       50 3.121594652591010478513182974309
N=      100 3.131592903558552764307414238276920516403
N=      500 3.1395926555897832385846406133805394790658
N=     1000 3.140592653839792925963596502869395970451
N=     5000 3.14139265359179323836264339547950011419817981883455
N=    10000 3.1414926535900432384595183833748153787870136427443
N=    50000 3.1415726535897952384626423832795041041971666293751159251748905370082151
N=   100000 3.1415826535897934884626433520295028937284193939649495759086359919592690
N=   500000 3.141590653589793240462643383269502884197291399375103050974944693349816400880678999026756787
N=  1000000 3.14159165358979323871264338327919038419717035250010581556478834235715332034804914389171886837074226037240467222525616602
N=  5000000 3.14159245358979323846464338327950278419716939938730582097494182230781640729662899862749427234211746670411008612545206374757482054463804148934888574594
N= 10000000 3.14159255358979323846289338327950288107216939937520113347494458689766015628670236776865975935664343518181611513876762898715961090779874943756416252087
N= 50000000 3.14159263358979323846264538327950288419616939937510582219494459230781363628620899863813902534211701392684808651368102860909384073124815323177345700314
N=100000000 3.14159264358979323846264363327950288419713814937510582098447584230781640087605274862803975903352331797554953915000106856
Exact:pi    3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940813
                                                                                                                 1         1         1         1         1         1
                       1         2         3         4         5         6         7         8         9         0         1         2         3         4         5
              123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890

  Items of Interest or for study:
  • It was quick and easy to convert the ordinary Python program to the arbitrary precision form.

  • Notice the ordinary integer variables mixed in on the right: N, sum, and k.

  • This series converges very slowly, so that with 1000000 terms we only get 6 correct digits of π. However, amazingly, the green digits show a large number of correct terms after incorrect ones. There are far too many for this to be random chance, although any given random digit ought to be correct with probability 1/10. Thus the isolated correct digits above, and even pairs of correct digits (with probability 1/100), might be correct by chance.

    These results suggest the existence of a sequence of correction terms that would make the final sum much more accurate. (See Gregory's Series for further explanation.)

  • The final run adding up 100000000 (one hundred million) terms of the series (using 120 digits precision) took 5 hours on my old PC at home. A 4-year-old Mac was about twice as fast. One can add improvements to the integer computations that will speed things up some (which I didn't do).

(Revision date: 2014-08-16. Please use ISO 8601, the International Standard.)