Esempio n. 1
0
def _apply_function_in_context(cls, f, args, context):
    """ Apply an MPFR function 'f' to the given arguments 'args', rounding to
    the given context.  Returns a new Mpfr object with precision taken from
    the current context.

    """
    rounding = context.rounding
    bf = mpfr.Mpfr_t.__new__(cls)
    mpfr.mpfr_init2(bf, context.precision)
    args = (bf,) + args + (rounding,)
    ternary = f(*args)
    with _temporary_exponent_bounds(context.emin, context.emax):
        ternary = mpfr.mpfr_check_range(bf, ternary, rounding)
        if context.subnormalize:
            # mpfr_subnormalize doesn't set underflow and
            # subnormal flags, so we do that ourselves.  We choose
            # to set the underflow flag for *all* cases where the
            # 'after rounding' result is smaller than the smallest
            # normal number, even if that result is exact.

            # if bf is zero but ternary is nonzero, the underflow
            # flag will already have been set by mpfr_check_range;
            underflow = (
                mpfr.mpfr_number_p(bf) and
                not mpfr.mpfr_zero_p(bf) and
                mpfr.mpfr_get_exp(bf) < context.precision - 1 + context.emin)
            if underflow:
                mpfr.mpfr_set_underflow()
            ternary = mpfr.mpfr_subnormalize(bf, ternary, rounding)
            if ternary:
                mpfr.mpfr_set_inexflag()
    return bf
Esempio n. 2
0
def _apply_function_in_context(cls, f, args, context):
    """ Apply an MPFR function 'f' to the given arguments 'args', rounding to
    the given context.  Returns a new Mpfr object with precision taken from
    the current context.

    """
    rounding = context.rounding
    bf = mpfr.Mpfr_t.__new__(cls)
    mpfr.mpfr_init2(bf, context.precision)
    args = (bf,) + args + (rounding,)
    ternary = f(*args)
    with _temporary_exponent_bounds(context.emin, context.emax):
        ternary = mpfr.mpfr_check_range(bf, ternary, rounding)
        if context.subnormalize:
            # mpfr_subnormalize doesn't set underflow and
            # subnormal flags, so we do that ourselves.  We choose
            # to set the underflow flag for *all* cases where the
            # 'after rounding' result is smaller than the smallest
            # normal number, even if that result is exact.

            # if bf is zero but ternary is nonzero, the underflow
            # flag will already have been set by mpfr_check_range;
            underflow = (
                mpfr.mpfr_number_p(bf) and
                not mpfr.mpfr_zero_p(bf) and
                mpfr.mpfr_get_exp(bf) < context.precision - 1 + context.emin)
            if underflow:
                mpfr.mpfr_set_underflow()
            ternary = mpfr.mpfr_subnormalize(bf, ternary, rounding)
            if ternary:
                mpfr.mpfr_set_inexflag()
    return bf
Esempio n. 3
0
def mpfr_mod(rop, x, y, rnd):
    """
    Given two MPRF numbers x and y, compute
    x - floor(x / y) * y, rounded if necessary using the given
    rounding mode.  The result is placed in 'rop'.

    This is the 'remainder' operation, with sign convention
    compatible with Python's % operator (where x % y has
    the same sign as y).
    """
    # There are various cases:
    #
    # 0. If either argument is a NaN, the result is NaN.
    #
    # 1. If x is infinite or y is zero, the result is NaN.
    #
    # 2. If y is infinite, return 0 with the sign of y if x is zero, x if x has
    #    the same sign as y, and infinity with the sign of y if it has the
    #    opposite sign.
    #
    # 3. If none of the above cases apply then both x and y are finite,
    #    and y is nonzero.  If x and y have the same sign, simply
    #    return the result of fmod(x, y).
    #
    # 4. Now both x and y are finite, y is nonzero, and x and y have
    #    differing signs.  Compute r = fmod(x, y) with sufficient precision
    #    to get an exact result.  If r == 0, return 0 with the sign of y
    #    (which will be the opposite of the sign of x).  If r != 0,
    #    return r + y, rounded appropriately.

    if not mpfr.mpfr_number_p(x) or mpfr.mpfr_nan_p(y) or mpfr.mpfr_zero_p(y):
        return mpfr.mpfr_fmod(rop, x, y, rnd)
    elif mpfr.mpfr_inf_p(y):
        x_negative = mpfr.mpfr_signbit(x)
        y_negative = mpfr.mpfr_signbit(y)
        if mpfr.mpfr_zero_p(x):
            mpfr.mpfr_set_zero(rop, -y_negative)
            return 0
        elif x_negative == y_negative:
            return mpfr.mpfr_set(rop, x, rnd)
        else:
            mpfr.mpfr_set_inf(rop, -y_negative)
            return 0

    x_negative = mpfr.mpfr_signbit(x)
    y_negative = mpfr.mpfr_signbit(y)
    if x_negative == y_negative:
        return mpfr.mpfr_fmod(rop, x, y, rnd)
    else:
        p = max(mpfr.mpfr_get_prec(x), mpfr.mpfr_get_prec(y))
        z = mpfr.Mpfr_t()
        mpfr.mpfr_init2(z, p)
        # Doesn't matter what rounding mode we use here; the result
        # should be exact.
        ternary = mpfr.mpfr_fmod(z, x, y, rnd)
        assert ternary == 0
        if mpfr.mpfr_zero_p(z):
            mpfr.mpfr_set_zero(rop, -y_negative)
            return 0
        else:
            return mpfr.mpfr_add(rop, y, z, rnd)