About arithmetic accuracy in Python

Table of Contents

In python, integers have arbitrary precision and therefore we can represent an arbitrarily large range of integers (only limited by the available memory).


In [1]:
x = 7**273
print(x)
print(type(x))


514949835672429280118340184962210764526557059561644551308225135656646772567852802341125202657808555553768425192667497268234055382589043229395747814284702360571674673819941501856557513477604134701802987908639670470095067188938102407
<class 'int'>

Python uses (hardware) 754 double precision representation for floats. This means that some floats can be only represented approximately.

  • Using string format to see the precision limitation of doubles in Python. For example, it is impossible to represent exactly the number 0.1:

In [2]:
format(0.1, '.80f')


Out[2]:
'0.10000000000000000555111512312578270211815834045410156250000000000000000000000000'
  • This can give us surprises:

In [3]:
.1 + .1 + .1 == .3


Out[3]:
False

In [4]:
.1  + .1 == .2


Out[4]:
True
  • For "infinite" precision float arithmetic you can use decimal or mpmath:

In [5]:
from decimal import Decimal, getcontext
  • Getting 30 digits of 1/7:

In [6]:
getcontext().prec=80
format(Decimal(1)/Decimal(7), '.80f')


Out[6]:
'0.14285714285714285714285714285714285714285714285714285714285714285714285714285714'
  • We can see how many digits are true of 1/7 using doubles:

In [7]:
format(1/7, '.80f')


Out[7]:
'0.14285714285714284921269268124888185411691665649414062500000000000000000000000000'

In [8]:
#12345678901234567 (17 digits)
  • Decimal arithmetic produces decimal objects:

In [9]:
Decimal(1)/Decimal(7)


Out[9]:
Decimal('0.14285714285714285714285714285714285714285714285714285714285714285714285714285714')
  • Decimal objects can be printed with format:

In [10]:
print('{:.50f}'.format(Decimal(1)/Decimal(7)))


0.14285714285714285714285714285714285714285714285714
$$ \pi = \sum_{k = 0}^{\infty}\Bigg[ \frac{1}{16^k} \left( \frac{4}{8k + 1} - \frac{2}{8k + 4} - \frac{1}{8k + 5} - \frac{1}{8k + 6} \right) \Bigg] $$

In [11]:
# https://stackoverflow.com/questions/28284996/python-pi-calculation
from decimal import Decimal, getcontext
getcontext().prec=1000
my_pi= sum(1/Decimal(16)**k * 
          (Decimal(4)/(8*k+1) - 
           Decimal(2)/(8*k+4) -
           Decimal(1)/(8*k+5) -
           Decimal(1)/(8*k+6)) for k in range(1000))
'{:.1000f}'.format(my_pi)


Out[11]:
'3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201930'

You can visit 100,000 Digits of Pi or One Million Digits of Pi to check the correctness this code.