Esempio n. 1
0
 def mag(ctx, x):
     """
     Quick logarithmic magnitude estimate of a number.
     Returns an integer or infinity `m` such that `|x| <= 2^m`.
     It is not guaranteed that `m` is an optimal bound,
     but it will never be off by more than 2 (and probably not
     more than 1).
     """
     if hasattr(x, "_mpf_"):
         return ctx._mpf_mag(x._mpf_)
     elif hasattr(x, "_mpc_"):
         r, i = x._mpc_
         if r == fzero:
             return ctx._mpf_mag(i)
         if i == fzero:
             return ctx._mpf_mag(r)
         return 1 + max(ctx._mpf_mag(r), ctx._mpf_mag(i))
     elif isinstance(x, int_types):
         if x:
             return bitcount(abs(x))
         return ctx.ninf
     elif isinstance(x, rational.mpq):
         p, q = x
         if p:
             return 1 + bitcount(abs(p)) - bitcount(abs(q))
         return ctx.ninf
     else:
         x = ctx.convert(x)
         if hasattr(x, "_mpf_") or hasattr(x, "_mpc_"):
             return ctx.mag(x)
         else:
             raise TypeError("requires an mpf/mpc")
Esempio n. 2
0
 def mag(ctx, x):
     """
     Quick logarithmic magnitude estimate of a number.
     Returns an integer or infinity `m` such that `|x| <= 2^m`.
     It is not guaranteed that `m` is an optimal bound,
     but it will never be off by more than 2 (and probably not
     more than 1).
     """
     if hasattr(x, "_mpf_"):
         return ctx._mpf_mag(x._mpf_)
     elif hasattr(x, "_mpc_"):
         r, i = x._mpc_
         if r == fzero:
             return ctx._mpf_mag(i)
         if i == fzero:
             return ctx._mpf_mag(r)
         return 1+max(ctx._mpf_mag(r), ctx._mpf_mag(i))
     elif isinstance(x, int_types):
         if x:
             return bitcount(abs(x))
         return ctx.ninf
     elif isinstance(x, rational.mpq):
         p, q = x
         if p:
             return 1 + bitcount(abs(p)) - bitcount(abs(q))
         return ctx.ninf
     else:
         x = ctx.convert(x)
         if hasattr(x, "_mpf_") or hasattr(x, "_mpc_"):
             return ctx.mag(x)
         else:
             raise TypeError("requires an mpf/mpc")
Esempio n. 3
0
 def __hash__(s):
     a, b = s._mpq_
     if b == 1:
         return hash(a)
     # Power of two: mpf compatible hash
     if not (b & (b - 1)):
         return mpf_hash(from_man_exp(a, 1 - bitcount(b)))
     return hash((a, b))
Esempio n. 4
0
 def __hash__(s):
     a, b = s._mpq_
     if b == 1:
         return hash(a)
     # Power of two: mpf compatible hash
     if not (b & (b-1)):
         return mpf_hash(from_man_exp(a, 1-bitcount(b)))
     return hash((a,b))
Esempio n. 5
0
    def mag(ctx, x):
        """
        Quick logarithmic magnitude estimate of a number. Returns an
        integer or infinity `m` such that `|x| <= 2^m`. It is not
        guaranteed that `m` is an optimal bound, but it will never
        be too large by more than 2 (and probably not more than 1).

        **Examples**

            >>> from mpmath import *
            >>> mp.pretty = True
            >>> mag(10), mag(10.0), mag(mpf(10)), int(ceil(log(10,2)))
            (4, 4, 4, 4)
            >>> mag(10j), mag(10+10j)
            (4, 5)
            >>> mag(0.01), int(ceil(log(0.01,2)))
            (-6, -6)
            >>> mag(0), mag(inf), mag(-inf), mag(nan)
            (-inf, +inf, +inf, nan)

        """
        if hasattr(x, "_mpf_"):
            return ctx._mpf_mag(x._mpf_)
        elif hasattr(x, "_mpc_"):
            r, i = x._mpc_
            if r == fzero:
                return ctx._mpf_mag(i)
            if i == fzero:
                return ctx._mpf_mag(r)
            return 1+max(ctx._mpf_mag(r), ctx._mpf_mag(i))
        elif isinstance(x, int_types):
            if x:
                return bitcount(abs(x))
            return ctx.ninf
        elif isinstance(x, rational.mpq):
            p, q = x._mpq_
            if p:
                return 1 + bitcount(abs(p)) - bitcount(q)
            return ctx.ninf
        else:
            x = ctx.convert(x)
            if hasattr(x, "_mpf_") or hasattr(x, "_mpc_"):
                return ctx.mag(x)
            else:
                raise TypeError("requires an mpf/mpc")
Esempio n. 6
0
    def mag(ctx, x):
        """
        Quick logarithmic magnitude estimate of a number. Returns an
        integer or infinity `m` such that `|x| <= 2^m`. It is not
        guaranteed that `m` is an optimal bound, but it will never
        be too large by more than 2 (and probably not more than 1).

        **Examples**

            >>> from mpmath import *
            >>> mp.pretty = True
            >>> mag(10), mag(10.0), mag(mpf(10)), int(ceil(log(10,2)))
            (4, 4, 4, 4)
            >>> mag(10j), mag(10+10j)
            (4, 5)
            >>> mag(0.01), int(ceil(log(0.01,2)))
            (-6, -6)
            >>> mag(0), mag(inf), mag(-inf), mag(nan)
            (-inf, +inf, +inf, nan)

        """
        if hasattr(x, "_mpf_"):
            return ctx._mpf_mag(x._mpf_)
        elif hasattr(x, "_mpc_"):
            r, i = x._mpc_
            if r == fzero:
                return ctx._mpf_mag(i)
            if i == fzero:
                return ctx._mpf_mag(r)
            return 1 + max(ctx._mpf_mag(r), ctx._mpf_mag(i))
        elif isinstance(x, int_types):
            if x:
                return bitcount(abs(x))
            return ctx.ninf
        elif isinstance(x, rational.mpq):
            p, q = x._mpq_
            if p:
                return 1 + bitcount(abs(p)) - bitcount(q)
            return ctx.ninf
        else:
            x = ctx.convert(x)
            if hasattr(x, "_mpf_") or hasattr(x, "_mpc_"):
                return ctx.mag(x)
            else:
                raise TypeError("requires an mpf/mpc")
Esempio n. 7
0
 def nint_distance(ctx, x):
     """
     Returns (n, d) where n is the nearest integer to x and d is the
     log-2 distance (i.e. distance in bits) of n from x. If d < 0,
     (-d) gives the bits of cancellation when n is subtracted from x.
     This function is intended to be used to check for cancellation
     at poles.
     """
     if hasattr(x, "_mpf_"):
         re = x._mpf_
         im_dist = ctx.ninf
     elif hasattr(x, "_mpc_"):
         re, im = x._mpc_
         isign, iman, iexp, ibc = im
         if iman:
             im_dist = iexp + ibc
         elif im == fzero:
             im_dist = ctx.ninf
         else:
             raise ValueError("requires a finite number")
     elif isinstance(x, int_types):
         return int(x), ctx.ninf
     elif isinstance(x, rational.mpq):
         p, q = x
         n, r = divmod(p, q)
         if 2*r >= q:
             n += 1
         elif not r:
             return n, ctx.ninf
         # log(p/q-n) = log((p-nq)/q) = log(p-nq) - log(q)
         d = bitcount(abs(p-n*q)) - bitcount(q)
         return n, d
     else:
         x = ctx.convert(x)
         if hasattr(x, "_mpf_") or hasattr(x, "_mpc_"):
             return ctx.nint_distance(x)
         else:
             raise TypeError("requires an mpf/mpc")
     sign, man, exp, bc = re
     shift = exp+bc
     if sign:
         man = -man
     if shift < -1:
         n = 0
         re_dist = shift
     elif man:
         if exp >= 0:
             n = man << exp
             re_dist = ctx.ninf
         else:
             if shift >= 0:
                 xfixed = man << shift
             else:
                 xfixed = man >> (-shift)
             n1 = xfixed >> bc
             n2 = -((-xfixed) >> bc)
             dist1 = abs(xfixed - (n1<<bc))
             dist2 = abs(xfixed - (n2<<bc))
             if dist1 < dist2:
                 re_dist = dist1
                 n = n1
             else:
                 re_dist = dist2
                 n = n2
             if re_dist:
                 re_dist = bitcount(re_dist) - bc
             else:
                 re_dist = ctx.ninf
     elif re == fzero:
         re_dist = ctx.ninf
         n = 0
     else:
         raise ValueError("requires a finite number")
     return n, max(re_dist, im_dist)
Esempio n. 8
0
    def nint_distance(ctx, x):
        r"""
        Return `(n,d)` where `n` is the nearest integer to `x` and `d` is
        an estimate of `\log_2(|x-n|)`. If `d < 0`, `-d` gives the precision
        (measured in bits) lost to cancellation when computing `x-n`.

            >>> from mpmath import *
            >>> n, d = nint_distance(5)
            >>> print n, d
            5 -inf
            >>> n, d = nint_distance(mpf(5))
            >>> print n, d
            5 -inf
            >>> n, d = nint_distance(mpf(5.00000001))
            >>> print n, d
            5 -26
            >>> n, d = nint_distance(mpf(4.99999999))
            >>> print n, d
            5 -26
            >>> n, d = nint_distance(mpc(5,10))
            >>> print n, d
            5 4
            >>> n, d = nint_distance(mpc(5,0.000001))
            >>> print n, d
            5 -19

        """
        if hasattr(x, "_mpf_"):
            re = x._mpf_
            im_dist = ctx.ninf
        elif hasattr(x, "_mpc_"):
            re, im = x._mpc_
            isign, iman, iexp, ibc = im
            if iman:
                im_dist = iexp + ibc
            elif im == fzero:
                im_dist = ctx.ninf
            else:
                raise ValueError("requires a finite number")
        elif isinstance(x, int_types):
            return int(x), ctx.ninf
        elif isinstance(x, rational.mpq):
            p, q = x._mpq_
            n, r = divmod(p, q)
            if 2*r >= q:
                n += 1
            elif not r:
                return n, ctx.ninf
            # log(p/q-n) = log((p-nq)/q) = log(p-nq) - log(q)
            d = bitcount(abs(p-n*q)) - bitcount(q)
            return n, d
        else:
            x = ctx.convert(x)
            if hasattr(x, "_mpf_") or hasattr(x, "_mpc_"):
                return ctx.nint_distance(x)
            else:
                raise TypeError("requires an mpf/mpc")
        sign, man, exp, bc = re
        shift = exp+bc
        if sign:
            man = -man
        if shift < -1:
            n = 0
            re_dist = shift
        elif man:
            if exp >= 0:
                n = man << exp
                re_dist = ctx.ninf
            else:
                if shift >= 0:
                    xfixed = man << shift
                else:
                    xfixed = man >> (-shift)
                n1 = xfixed >> bc
                n2 = -((-xfixed) >> bc)
                dist1 = abs(xfixed - (n1<<bc))
                dist2 = abs(xfixed - (n2<<bc))
                if dist1 < dist2:
                    re_dist = dist1
                    n = n1
                else:
                    re_dist = dist2
                    n = n2
                if re_dist:
                    re_dist = bitcount(re_dist) - bc
                else:
                    re_dist = ctx.ninf
        elif re == fzero:
            re_dist = ctx.ninf
            n = 0
        else:
            raise ValueError("requires a finite number")
        return n, max(re_dist, im_dist)
Esempio n. 9
0
    def nint_distance(ctx, x):
        r"""
        Return `(n,d)` where `n` is the nearest integer to `x` and `d` is
        an estimate of `\log_2(|x-n|)`. If `d < 0`, `-d` gives the precision
        (measured in bits) lost to cancellation when computing `x-n`.

            >>> from mpmath import *
            >>> n, d = nint_distance(5)
            >>> print n, d
            5 -inf
            >>> n, d = nint_distance(mpf(5))
            >>> print n, d
            5 -inf
            >>> n, d = nint_distance(mpf(5.00000001))
            >>> print n, d
            5 -26
            >>> n, d = nint_distance(mpf(4.99999999))
            >>> print n, d
            5 -26
            >>> n, d = nint_distance(mpc(5,10))
            >>> print n, d
            5 4
            >>> n, d = nint_distance(mpc(5,0.000001))
            >>> print n, d
            5 -19

        """
        typx = type(x)
        if typx in int_types:
            return int(x), ctx.ninf
        elif typx is rational.mpq:
            p, q = x._mpq_
            n, r = divmod(p, q)
            if 2*r >= q:
                n += 1
            elif not r:
                return n, ctx.ninf
            # log(p/q-n) = log((p-nq)/q) = log(p-nq) - log(q)
            d = bitcount(abs(p-n*q)) - bitcount(q)
            return n, d
        if hasattr(x, "_mpf_"):
            re = x._mpf_
            im_dist = ctx.ninf
        elif hasattr(x, "_mpc_"):
            re, im = x._mpc_
            isign, iman, iexp, ibc = im
            if iman:
                im_dist = iexp + ibc
            elif im == fzero:
                im_dist = ctx.ninf
            else:
                raise ValueError("requires a finite number")
        else:
            x = ctx.convert(x)
            if hasattr(x, "_mpf_") or hasattr(x, "_mpc_"):
                return ctx.nint_distance(x)
            else:
                raise TypeError("requires an mpf/mpc")
        sign, man, exp, bc = re
        mag = exp+bc
        # |x| < 0.5
        if mag < 0:
            n = 0
            re_dist = mag
        elif man:
            # exact integer
            if exp >= 0:
                n = man << exp
                re_dist = ctx.ninf
            # exact half-integer
            elif exp == -1:
                n = (man>>1)+1
                re_dist = 0
            else:
                d = (-exp-1)
                t = man >> d
                if t & 1:
                    t += 1
                    man = (t<<d) - man
                else:
                    man -= (t<<d)
                n = t>>1   # int(t)>>1
                re_dist = exp+bitcount(man)
            if sign:
                n = -n
        elif re == fzero:
            re_dist = ctx.ninf
            n = 0
        else:
            raise ValueError("requires a finite number")
        return n, max(re_dist, im_dist)