def mpi_pow_int(s, n, prec): sa, sb = s if n < 0: return mpi_div((fone, fone), mpi_pow_int(s, -n, prec + 20), prec) if n == 0: return (fone, fone) if n == 1: return s # Odd -- signs are preserved if n & 1: a = mpf_pow_int(sa, n, prec, round_floor) b = mpf_pow_int(sb, n, prec, round_ceiling) # Even -- important to ensure positivity else: sas = mpf_sign(sa) sbs = mpf_sign(sb) # Nonnegative? if sas >= 0: a = mpf_pow_int(sa, n, prec, round_floor) b = mpf_pow_int(sb, n, prec, round_ceiling) # Nonpositive? elif sbs <= 0: a = mpf_pow_int(sb, n, prec, round_floor) b = mpf_pow_int(sa, n, prec, round_ceiling) # Mixed signs? else: a = fzero # max(-a,b)**n sa = mpf_neg(sa) if mpf_ge(sa, sb): b = mpf_pow_int(sa, n, prec, round_ceiling) else: b = mpf_pow_int(sb, n, prec, round_ceiling) return a, b
def mpi_pow_int(s, n, prec): sa, sb = s if n < 0: return mpi_div((fone, fone), mpi_pow_int(s, -n, prec+20), prec) if n == 0: return (fone, fone) if n == 1: return s # Odd -- signs are preserved if n & 1: a = mpf_pow_int(sa, n, prec, round_floor) b = mpf_pow_int(sb, n, prec, round_ceiling) # Even -- important to ensure positivity else: sas = mpf_sign(sa) sbs = mpf_sign(sb) # Nonnegative? if sas >= 0: a = mpf_pow_int(sa, n, prec, round_floor) b = mpf_pow_int(sb, n, prec, round_ceiling) # Nonpositive? elif sbs <= 0: a = mpf_pow_int(sb, n, prec, round_floor) b = mpf_pow_int(sa, n, prec, round_ceiling) # Mixed signs? else: a = fzero # max(-a,b)**n sa = mpf_neg(sa) if mpf_ge(sa, sb): b = mpf_pow_int(sa, n, prec, round_ceiling) else: b = mpf_pow_int(sb, n, prec, round_ceiling) return a, b
def mpi_div(s, t, prec): sa, sb = s ta, tb = t sas = mpf_sign(sa) sbs = mpf_sign(sb) tas = mpf_sign(ta) tbs = mpf_sign(tb) # 0 / X if sas == sbs == 0: # 0 / <interval containing 0> if (tas < 0 and tbs > 0) or (tas == 0 or tbs == 0): return fninf, finf return fzero, fzero # Denominator contains both negative and positive numbers; # this should properly be a multi-interval, but the closest # match is the entire (extended) real line if tas < 0 and tbs > 0: return fninf, finf # Assume denominator to be nonnegative if tas < 0: return mpi_div(mpi_neg(s), mpi_neg(t), prec) # Division by zero # XXX: make sure all results make sense if tas == 0: # Numerator contains both signs? if sas < 0 and sbs > 0: return fninf, finf if tas == tbs: return fninf, finf # Numerator positive? if sas >= 0: a = mpf_div(sa, tb, prec, round_floor) b = finf if sbs <= 0: a = fninf b = mpf_div(sb, tb, prec, round_ceiling) # Division with positive denominator # We still have to handle nans resulting from inf/0 or inf/inf else: # Nonnegative numerator if sas >= 0: a = mpf_div(sa, tb, prec, round_floor) b = mpf_div(sb, ta, prec, round_ceiling) if a == fnan: a = fzero if b == fnan: b = finf # Nonpositive numerator elif sbs <= 0: a = mpf_div(sa, ta, prec, round_floor) b = mpf_div(sb, tb, prec, round_ceiling) if a == fnan: a = fninf if b == fnan: b = fzero # Numerator contains both signs? else: a = mpf_div(sa, ta, prec, round_floor) b = mpf_div(sb, ta, prec, round_ceiling) if a == fnan: a = fninf if b == fnan: b = finf return a, b
def mpf_atan2(y, x, prec, rnd=round_fast): xsign, xman, xexp, xbc = x ysign, yman, yexp, ybc = y if not yman: if y == fnan or x == fnan: return fnan if mpf_sign(x) >= 0: return fzero return mpf_pi(prec, rnd) if ysign: return mpf_neg(mpf_atan2(mpf_neg(y), x, prec, rnd)) if not xman: if x == fnan: return fnan if x == finf: return fzero if x == fninf: return mpf_pi(prec, rnd) if not yman: return fzero return mpf_shift(mpf_pi(prec, rnd), -1) tquo = mpf_atan(mpf_div(y, x, prec+4), prec+4) if xsign: return mpf_add(mpf_pi(prec+4), tquo, prec, rnd) else: return mpf_pos(tquo, prec, rnd)
def mpf_atan2(y, x, prec, rnd=round_fast): xsign, xman, xexp, xbc = x ysign, yman, yexp, ybc = y if not yman: if y == fzero and x != fnan: if mpf_sign(x) >= 0: return fzero return mpf_pi(prec, rnd) if y in (finf, fninf): if x in (finf, fninf): return fnan # pi/2 if y == finf: return mpf_shift(mpf_pi(prec, rnd), -1) # -pi/2 return mpf_neg(mpf_shift(mpf_pi(prec, negative_rnd[rnd]), -1)) return fnan if ysign: return mpf_neg(mpf_atan2(mpf_neg(y), x, prec, negative_rnd[rnd])) if not xman: if x == fnan: return fnan if x == finf: return fzero if x == fninf: return mpf_pi(prec, rnd) if y == fzero: return fzero return mpf_shift(mpf_pi(prec, rnd), -1) tquo = mpf_atan(mpf_div(y, x, prec+4), prec+4) if xsign: return mpf_add(mpf_pi(prec+4), tquo, prec, rnd) else: return mpf_pos(tquo, prec, rnd)
def mpf_atan2(y, x, prec, rnd=round_fast): xsign, xman, xexp, xbc = x ysign, yman, yexp, ybc = y if not yman: if y == fnan or x == fnan: return fnan if mpf_sign(x) >= 0: return fzero return mpf_pi(prec, rnd) if ysign: return mpf_neg(mpf_atan2(mpf_neg(y), x, prec, rnd)) if not xman: if x == fnan: return fnan if x == finf: return fzero if x == fninf: return mpf_pi(prec, rnd) if not yman: return fzero return mpf_shift(mpf_pi(prec, rnd), -1) tquo = mpf_atan(mpf_div(y, x, prec + 4), prec + 4) if xsign: return mpf_add(mpf_pi(prec + 4), tquo, prec, rnd) else: return mpf_pos(tquo, prec, rnd)
def mpi_abs(s, prec): sa, sb = s sas = mpf_sign(sa) sbs = mpf_sign(sb) # Both points nonnegative? if sas >= 0: a = mpf_pos(sa, prec, round_floor) b = mpf_pos(sb, prec, round_ceiling) # Upper point nonnegative? elif sbs >= 0: a = fzero negsa = mpf_neg(sa) if mpf_lt(negsa, sb): b = mpf_pos(sb, prec, round_ceiling) else: b = mpf_pos(negsa, prec, round_ceiling) # Both negative? else: a = mpf_neg(sb, prec, round_floor) b = mpf_neg(sa, prec, round_ceiling) return a, b
def mpc_ci(z, prec, rnd=round_fast): re, im = z if im == fzero: ci = mpf_ci_si(re, prec, rnd, 0)[0] if mpf_sign(re) < 0: return (ci, mpf_pi(prec, rnd)) return (ci, fzero) wp = prec + 20 cre, cim = mpc_ci_si_taylor(re, im, wp, 0) cre = mpf_add(cre, mpf_euler(wp), wp) ci = mpc_add((cre, cim), mpc_log(z, wp), prec, rnd) return ci
def mpi_mul(s, t, prec): sa, sb = s ta, tb = t sas = mpf_sign(sa) sbs = mpf_sign(sb) tas = mpf_sign(ta) tbs = mpf_sign(tb) if sas == sbs == 0: # Should maybe be undefined if ta == fninf or tb == finf: return fninf, finf return fzero, fzero if tas == tbs == 0: # Should maybe be undefined if sa == fninf or sb == finf: return fninf, finf return fzero, fzero if sas >= 0: # positive * positive if tas >= 0: a = mpf_mul(sa, ta, prec, round_floor) b = mpf_mul(sb, tb, prec, round_ceiling) if a == fnan: a = fzero if b == fnan: b = finf # positive * negative elif tbs <= 0: a = mpf_mul(sb, ta, prec, round_floor) b = mpf_mul(sa, tb, prec, round_ceiling) if a == fnan: a = fninf if b == fnan: b = fzero # positive * both signs else: a = mpf_mul(sb, ta, prec, round_floor) b = mpf_mul(sb, tb, prec, round_ceiling) if a == fnan: a = fninf if b == fnan: b = finf elif sbs <= 0: # negative * positive if tas >= 0: a = mpf_mul(sa, tb, prec, round_floor) b = mpf_mul(sb, ta, prec, round_ceiling) if a == fnan: a = fninf if b == fnan: b = fzero # negative * negative elif tbs <= 0: a = mpf_mul(sb, tb, prec, round_floor) b = mpf_mul(sa, ta, prec, round_ceiling) if a == fnan: a = fzero if b == fnan: b = finf # negative * both signs else: a = mpf_mul(sa, tb, prec, round_floor) b = mpf_mul(sa, ta, prec, round_ceiling) if a == fnan: a = fninf if b == fnan: b = finf else: # General case: perform all cross-multiplications and compare # Since the multiplications can be done exactly, we need only # do 4 (instead of 8: two for each rounding mode) cases = [mpf_mul(sa, ta), mpf_mul(sa, tb), mpf_mul(sb, ta), mpf_mul(sb, tb)] if fnan in cases: a, b = (fninf, finf) else: cases = sorted(cases, cmp=mpf_cmp) a = mpf_pos(cases[0], prec, round_floor) b = mpf_pos(cases[-1], prec, round_ceiling) return a, b
def mpi_mul(s, t, prec): sa, sb = s ta, tb = t sas = mpf_sign(sa) sbs = mpf_sign(sb) tas = mpf_sign(ta) tbs = mpf_sign(tb) if sas == sbs == 0: # Should maybe be undefined if ta == fninf or tb == finf: return fninf, finf return fzero, fzero if tas == tbs == 0: # Should maybe be undefined if sa == fninf or sb == finf: return fninf, finf return fzero, fzero if sas >= 0: # positive * positive if tas >= 0: a = mpf_mul(sa, ta, prec, round_floor) b = mpf_mul(sb, tb, prec, round_ceiling) if a == fnan: a = fzero if b == fnan: b = finf # positive * negative elif tbs <= 0: a = mpf_mul(sb, ta, prec, round_floor) b = mpf_mul(sa, tb, prec, round_ceiling) if a == fnan: a = fninf if b == fnan: b = fzero # positive * both signs else: a = mpf_mul(sb, ta, prec, round_floor) b = mpf_mul(sb, tb, prec, round_ceiling) if a == fnan: a = fninf if b == fnan: b = finf elif sbs <= 0: # negative * positive if tas >= 0: a = mpf_mul(sa, tb, prec, round_floor) b = mpf_mul(sb, ta, prec, round_ceiling) if a == fnan: a = fninf if b == fnan: b = fzero # negative * negative elif tbs <= 0: a = mpf_mul(sb, tb, prec, round_floor) b = mpf_mul(sa, ta, prec, round_ceiling) if a == fnan: a = fzero if b == fnan: b = finf # negative * both signs else: a = mpf_mul(sb, tb, prec, round_floor) b = mpf_mul(sa, ta, prec, round_ceiling) if a == fnan: a = fninf if b == fnan: b = finf else: # General case: perform all cross-multiplications and compare # Since the multiplications can be done exactly, we need only # do 4 (instead of 8: two for each rounding mode) cases = [mpf_mul(sa, ta), mpf_mul(sa, tb), mpf_mul(sb, ta), mpf_mul(sb, tb)] if fnan in cases: a, b = (fninf, finf) else: cases = sorted(cases, cmp=mpf_cmp) a = mpf_pos(cases[0], prec, round_floor) b = mpf_pos(cases[-1], prec, round_ceiling) return a, b
def mpf_ci(x, prec, rnd=round_fast): if mpf_sign(x) < 0: raise ComplexResult return mpf_ci_si(x, prec, rnd, 0)[0]