[Tutor] more precision/predictability in calculations [gmpy module]

Daniel Yoo dyoo@CSUA.Berkeley.EDU
Fri, 13 Sep 2002 00:36:48 -0700 (PDT)


On Fri, 13 Sep 2002, Prahlad Vaidyanathan wrote:

> def diff2 (fn, var, x0, y0, epsilon=0.0001) :
>     """ Given a 2 variable function, differentiates it partially
>     w.r.t 'var', at the point (x0, y0) """
>     if var == "x" :
>         return (fn(x0+epsilon, y0) - fn(x0, y0))/epsilon
>     elif var == "y" :
>         return (fn(x0, y0+epsilon) - fn(x0, y0))/epsilon
>
> def satisfies_cr_eqns (u, v, z0) :
>     """Checks if the 2 real-valued functions 'u' and 'v' satisfy
>     the Cauchy-Reimann equations at z0"""
>     ux = diff2(u, "x", z0.real, z0.imag) ##; print ux
>     uy = diff2(u, "y", z0.real, z0.imag) ##; print uy
>     vx = diff2(v, "x", z0.real, z0.imag) ##; print vx
>     vy = diff2(v, "y", z0.real, z0.imag) ##; print vy
>     ## return ux == vy and uy == -vx
>     return (ux - vy) < pow(10,-3) and (uy + vx) < pow(10, -3)
>
> """
>
>     Now, I construct 2 functions like so :
>
> """
>
> def f1(a, b) :
>     return pow(math.e, a) * math.cos(b)
>
> def f2(a, b) :
>     return pow(math.e, a) * math.sin(b)
>
> """
>
>     These 2 functions do satisfy the c-r equations for any point in the
> complex plane.

?!?  Waaaa....  *grin*


> But, when I run satisfy_cr_eqns(), it returns true for some points and
> false for others. I presumed that the higher the value of the complex
> number, the lower the precision would be. But, the function turns out to
> be true for complex(99,99), and false for complex(3,3) !!
>
>     I know this may be asking too much of Python, but is there any way I
> can make these calculations more precise ? or, at least more predictable
> ? :-)


Python uses floating point to represent these numbers, so that's where
we're losing precision.  We can probably do a bit better by using the
'gmp' General MultiPrecision library --- it's made to handle hardcore
arbitrary precision arithmetic:

    http://www.swox.com/gmp/


There's are a few Python wrappers around portions of the GMP library, and
we can find a good one in the 'gmpy' module:

    http://gmpy.sourceforge.net/


The gmpy module provides a function called 'mpf()', which constructs
multi-precision floats.  The documentation is a little terse, so here's a
small example:

###
>>> import gmpy
>>> mpf = gmpy.mpf
>>> mpf('3.1415926')
mpf('3.1415926e0')
>>> pi = mpf('3.1415926')
>>> pi / mpf(10**100000)
mpf('3.1415926e-100000')
###

The last example is somewhat neat, considering that it doesn't work (at
least, not easily) in standard Python:

###
>>> 3.1415926 / 10**100000
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
OverflowError: long int too large to convert to float
###


The gmpy module should come with a test file called 'gmpy_test_08_mpf.py'
that showcases the sort of precision we can expect from these numbers.




Best of wishes to you!