Search code examples
pythonmathprecisiongmp

gmpy2: How do I track precision of mpc operations?


Say I have two gmpy2.mpc objects x and y precise to p bits. When I compute x+y it may be that some parts of x and y cancel so I'm left with less precision.

For example

from gmpy2 import *

x = mpc('-0.55555')
y = mpc('0.5555500000001')
print(x+y)

The result is precise to only 4 significant figures even though x and y were precise to ~15.

I think I need to work out how many bits of cancellation occur when I do addition and subtraction and then take this away from the minimum of x or y's precision. For multiplication and division I think I will only lose 1 bit of precision at most.

So the question is quite general: how can I keep track of the precision of mpc objects, particularly when adding and subtracting them?


Solution

  • The following function will return the numbers of matching bits of two mpfr objects.

    import gmpy2
    
    def matching_bits(x, y):
        '''Returns the number of bits that match between x and y. The
        sign of x and y are ignored. x and y must be of type mpfr.'''
    
        # Force both values to be positive, and x >= y.
        x = abs(x)
        y = abs(y)
        if x < y:
            x, y = y, x
    
        if not isinstance(x, type(gmpy2.mpfr(0))) or not isinstance(y, type(gmpy2.mpfr(0))):
            raise TypeError("Arguments must be of type 'mpfr'.")
    
        x_bits, x_exp, x_prec = x.digits(2)
        y_bits, y_exp, y_prec = y.digits(2)
    
        # (x_exp - y_exp) is the number of zeros that must be prepended
        # to x to align the mantissas. If that is greater than the precision
        # y, then no bits in common.
        if (x_exp - y_exp) > x_prec:
            return 0
    
        x_bits = "0" * (x_exp - y_exp) + x_bits
    
        count = 0
        while count < min(x_prec, y_prec) and x_bits[count] == y_bits[count]:
            count += 1
        return count
    

    I haven't extensively tested this function but it should give you a start. You will need to check the real and imaginary components separately. You'll probably want to modify it to check for sign and whether you are performing addition vs. subtraction.