Repository: mpmath/mpmath
Pull request #703 (2023-05-19 08:52:47)

Misc fixes


Patch:
diff --git a/mpmath/ctx_mp.py b/mpmath/ctx_mp.py
index c17017e..bf9cd6c 100644
--- a/mpmath/ctx_mp.py
+++ b/mpmath/ctx_mp.py
@@ -5,6 +5,7 @@
 
 import functools
 import re
+import warnings
 
 from . import function_docs, libmp
 from .ctx_base import StandardBaseContext
@@ -22,6 +23,13 @@
 get_complex = re.compile(r'^\(?(?P<re>[\+\-]?\d*(\.\d*)?(e[\+\-]?\d+)?)??'
                          r'(?P<im>[\+\-]?\d*(\.\d*)?(e[\+\-]?\d+)?j)?\)?$')
 
+def __getattr__(name):
+    if name == 'mpnumeric':
+        from .ctx_mp_python import mpnumeric
+        warnings.warn(f"{name} is deprecated", DeprecationWarning)
+        return mpnumeric
+    raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
+
 if BACKEND == 'sage':
     # pickle hack
     import sage.libs.mpmath.ext_main as _mpf_module
@@ -666,7 +674,7 @@ def hypsum(ctx, p, q, flags, coeffs, z, accurate_small=True, **kwargs):
             max_total_jump += abs(d)
         while 1:
             if extraprec > maxprec:
-                raise ValueError(ctx._hypsum_msg % (prec, prec+extraprec))
+                raise ctx.NoConvergence(ctx._hypsum_msg % (prec, prec+extraprec))
             wp = prec + extraprec
             if magnitude_check:
                 mag_dict = dict((n,None) for n in magnitude_check)
diff --git a/mpmath/functions/hypergeometric.py b/mpmath/functions/hypergeometric.py
index c83c7b1..63d671b 100644
--- a/mpmath/functions/hypergeometric.py
+++ b/mpmath/functions/hypergeometric.py
@@ -442,7 +442,11 @@ def _hyp2f1(ctx, a_s, b_s, z, **kwargs):
     # possibly in finitely many terms
     if absz <= 0.8 or (ctx.isint(a) and a <= 0 and a >= -1000) or \
                       (ctx.isint(b) and b <= 0 and b >= -1000):
-        return ctx.hypsum(2, 1, (atype, btype, ctype), [a, b, c], z, **kwargs)
+        try:
+            return ctx.hypsum(2, 1, (atype, btype, ctype), [a, b, c], z, **kwargs)
+        except ctx.NoConvergence:
+            if kwargs.get('force_series', False):
+                raise
 
     orig = ctx.prec
     try:
diff --git a/mpmath/libmp/__init__.py b/mpmath/libmp/__init__.py
index bb7abc5..6445056 100644
--- a/mpmath/libmp/__init__.py
+++ b/mpmath/libmp/__init__.py
@@ -1,77 +1,69 @@
-from .libmpf import (prec_to_dps, dps_to_prec, repr_dps,
-  round_down, round_up, round_floor, round_ceiling, round_nearest,
-  to_pickable, from_pickable, ComplexResult,
-  fzero, fnzero, fone, fnone, ftwo, ften, fhalf, fnan, finf, fninf,
-  math_float_inf, round_int, normalize,
-  from_man_exp, from_int, to_man_exp, to_int, mpf_ceil, mpf_floor,
-  mpf_nint, mpf_frac,
-  from_float, from_npfloat, from_Decimal, to_float, from_rational, to_rational, to_fixed,
-  mpf_rand, mpf_eq, mpf_hash, mpf_cmp, mpf_lt, mpf_le, mpf_gt, mpf_ge,
-  mpf_pos, mpf_neg, mpf_abs, mpf_sign, mpf_add, mpf_sub, mpf_sum,
-  mpf_mul, mpf_mul_int, mpf_shift, mpf_frexp,
-  mpf_div, mpf_rdiv_int, mpf_mod, mpf_pow_int,
-  mpf_perturb,
-  to_digits_exp, to_str, str_to_man_exp, from_str, from_bstr, to_bstr,
-  mpf_sqrt, mpf_hypot)
-
-from .libmpc import (mpc_one, mpc_zero, mpc_two, mpc_half,
-  mpc_is_inf, mpc_is_infnan, mpc_to_str, mpc_to_complex, mpc_hash,
-  mpc_conjugate, mpc_is_nonzero, mpc_add, mpc_add_mpf,
-  mpc_sub, mpc_sub_mpf, mpc_pos, mpc_neg, mpc_shift, mpc_abs,
-  mpc_arg, mpc_floor, mpc_ceil,  mpc_nint, mpc_frac, mpc_mul, mpc_square,
-  mpc_mul_mpf, mpc_mul_imag_mpf, mpc_mul_int,
-  mpc_div, mpc_div_mpf, mpc_reciprocal, mpc_mpf_div,
-  complex_int_pow, mpc_pow, mpc_pow_mpf, mpc_pow_int,
-  mpc_sqrt, mpc_nthroot, mpc_cbrt, mpc_exp, mpc_log, mpc_cos, mpc_sin,
-  mpc_tan, mpc_cos_pi, mpc_sin_pi, mpc_cosh, mpc_sinh, mpc_tanh,
-  mpc_atan, mpc_acos, mpc_asin, mpc_asinh, mpc_acosh, mpc_atanh,
-  mpc_fibonacci, mpf_expj, mpf_expjpi, mpc_expj, mpc_expjpi,
-  mpc_cos_sin, mpc_cos_sin_pi)
-
-from .libelefun import (ln2_fixed, mpf_ln2, ln10_fixed, mpf_ln10,
-  pi_fixed, mpf_pi, e_fixed, mpf_e, phi_fixed, mpf_phi,
-  degree_fixed, mpf_degree,
-  mpf_pow, mpf_nthroot, mpf_cbrt, log_int_fixed, agm_fixed,
-  mpf_log, mpf_log_hypot, mpf_exp, mpf_cos_sin, mpf_cos, mpf_sin, mpf_tan,
-  mpf_cos_sin_pi, mpf_cos_pi, mpf_sin_pi, mpf_cosh_sinh,
-  mpf_cosh, mpf_sinh, mpf_tanh, mpf_atan, mpf_atan2, mpf_asin,
-  mpf_acos, mpf_asinh, mpf_acosh, mpf_atanh, mpf_fibonacci)
-
-from .libhyper import (NoConvergence, make_hyp_summator,
-  mpf_erf, mpf_erfc, mpf_ei, mpc_ei, mpf_e1, mpc_e1, mpf_expint,
-  mpf_ci_si, mpf_ci, mpf_si, mpc_ci, mpc_si, mpf_besseljn,
-  mpc_besseljn, mpf_agm, mpf_agm1, mpc_agm, mpc_agm1,
-  mpf_ellipk, mpc_ellipk, mpf_ellipe, mpc_ellipe)
-
-from .gammazeta import (catalan_fixed, mpf_catalan,
-  khinchin_fixed, mpf_khinchin, glaisher_fixed, mpf_glaisher,
-  apery_fixed, mpf_apery, euler_fixed, mpf_euler, mertens_fixed,
-  mpf_mertens, twinprime_fixed, mpf_twinprime,
-  mpf_bernoulli, bernfrac, mpf_gamma_int,
-  mpf_factorial, mpc_factorial, mpf_gamma, mpc_gamma,
-  mpf_loggamma, mpc_loggamma, mpf_rgamma, mpc_rgamma,
-  mpf_harmonic, mpc_harmonic, mpf_psi0, mpc_psi0,
-  mpf_psi, mpc_psi, mpf_zeta_int, mpf_zeta, mpc_zeta,
-  mpf_altzeta, mpc_altzeta, mpf_zetasum, mpc_zetasum)
-
-from .libmpi import (mpi_str,
-  mpi_from_str, mpi_to_str,
-  mpi_eq, mpi_ne,
-  mpi_lt, mpi_le, mpi_gt, mpi_ge,
-  mpi_add, mpi_sub, mpi_delta, mpi_mid,
-  mpi_pos, mpi_neg, mpi_abs, mpi_mul, mpi_div, mpi_exp,
-  mpi_log, mpi_sqrt, mpi_pow_int, mpi_pow, mpi_cos_sin,
-  mpi_cos, mpi_sin, mpi_tan, mpi_cot,
-  mpi_atan, mpi_atan2,
-  mpci_pos, mpci_neg, mpci_add, mpci_sub, mpci_mul, mpci_div, mpci_pow,
-  mpci_abs, mpci_pow, mpci_exp, mpci_log, mpci_cos, mpci_sin,
-  mpi_gamma, mpci_gamma, mpi_loggamma, mpci_loggamma,
-  mpi_rgamma, mpci_rgamma, mpi_factorial, mpci_factorial)
-
-from .libintmath import (trailing, bitcount, numeral, bin_to_radix,
-  isqrt, isqrt_small, isqrt_fast, sqrt_fixed, sqrtrem, ifib, ifac,
-  list_primes, isprime, moebius, gcd, eulernum, stirling1, stirling2)
-
-from .backend import (gmpy, sage, BACKEND, STRICT, MPZ, MPQ,
-  MPZ_ZERO, MPZ_ONE, MPZ_TWO, MPZ_THREE, MPZ_FIVE, int_types,
-  HASH_MODULUS, HASH_BITS)
+from .backend import (BACKEND, HASH_BITS, HASH_MODULUS, MPQ, MPZ, MPZ_FIVE,
+                      MPZ_ONE, MPZ_THREE, MPZ_TWO, MPZ_ZERO, STRICT, gmpy,
+                      int_types, sage)
+from .gammazeta import (apery_fixed, bernfrac, catalan_fixed, euler_fixed,
+                        glaisher_fixed, khinchin_fixed, mertens_fixed,
+                        mpc_altzeta, mpc_factorial, mpc_gamma, mpc_harmonic,
+                        mpc_loggamma, mpc_psi, mpc_psi0, mpc_rgamma, mpc_zeta,
+                        mpc_zetasum, mpf_altzeta, mpf_apery, mpf_bernoulli,
+                        mpf_catalan, mpf_euler, mpf_factorial, mpf_gamma,
+                        mpf_gamma_int, mpf_glaisher, mpf_harmonic,
+                        mpf_khinchin, mpf_loggamma, mpf_mertens, mpf_psi,
+                        mpf_psi0, mpf_rgamma, mpf_twinprime, mpf_zeta,
+                        mpf_zeta_int, mpf_zetasum, twinprime_fixed)
+from .libelefun import (agm_fixed, degree_fixed, e_fixed, ln2_fixed,
+                        ln10_fixed, log_int_fixed, mpf_acos, mpf_acosh,
+                        mpf_asin, mpf_asinh, mpf_atan, mpf_atan2, mpf_atanh,
+                        mpf_cbrt, mpf_cos, mpf_cos_pi, mpf_cos_sin,
+                        mpf_cos_sin_pi, mpf_cosh, mpf_cosh_sinh, mpf_degree,
+                        mpf_e, mpf_exp, mpf_fibonacci, mpf_ln2, mpf_ln10,
+                        mpf_log, mpf_log_hypot, mpf_nthroot, mpf_phi, mpf_pi,
+                        mpf_pow, mpf_sin, mpf_sin_pi, mpf_sinh, mpf_tan,
+                        mpf_tanh, phi_fixed, pi_fixed)
+from .libhyper import (NoConvergence, make_hyp_summator, mpc_agm, mpc_agm1,
+                       mpc_besseljn, mpc_ci, mpc_e1, mpc_ei, mpc_ellipe,
+                       mpc_ellipk, mpc_si, mpf_agm, mpf_agm1, mpf_besseljn,
+                       mpf_ci, mpf_ci_si, mpf_e1, mpf_ei, mpf_ellipe,
+                       mpf_ellipk, mpf_erf, mpf_erfc, mpf_expint, mpf_si)
+from .libintmath import (bin_to_radix, bitcount, eulernum, gcd, ifac, ifib,
+                         isprime, isqrt, isqrt_fast, isqrt_small, list_primes,
+                         moebius, numeral, sqrt_fixed, sqrtrem, stirling1,
+                         stirling2, trailing)
+from .libmpc import (complex_int_pow, mpc_abs, mpc_acos, mpc_acosh, mpc_add,
+                     mpc_add_mpf, mpc_arg, mpc_asin, mpc_asinh, mpc_atan,
+                     mpc_atanh, mpc_cbrt, mpc_ceil, mpc_conjugate, mpc_cos,
+                     mpc_cos_pi, mpc_cos_sin, mpc_cos_sin_pi, mpc_cosh,
+                     mpc_div, mpc_div_mpf, mpc_exp, mpc_expj, mpc_expjpi,
+                     mpc_fibonacci, mpc_floor, mpc_frac, mpc_half, mpc_hash,
+                     mpc_is_inf, mpc_is_infnan, mpc_is_nonzero, mpc_log,
+                     mpc_mpf_div, mpc_mul, mpc_mul_imag_mpf, mpc_mul_int,
+                     mpc_mul_mpf, mpc_neg, mpc_nint, mpc_nthroot, mpc_one,
+                     mpc_pos, mpc_pow, mpc_pow_int, mpc_pow_mpf,
+                     mpc_reciprocal, mpc_shift, mpc_sin, mpc_sin_pi, mpc_sinh,
+                     mpc_sqrt, mpc_square, mpc_sub, mpc_sub_mpf, mpc_tan,
+                     mpc_tanh, mpc_to_complex, mpc_to_str, mpc_two, mpc_zero,
+                     mpf_expj, mpf_expjpi)
+from .libmpf import (ComplexResult, dps_to_prec, fhalf, finf, fnan, fninf,
+                     fnone, fnzero, fone, from_Decimal, from_float, from_int,
+                     from_man_exp, from_npfloat, from_pickable, from_rational,
+                     from_str, ften, ftwo, fzero, math_float_inf, mpf_abs,
+                     mpf_add, mpf_ceil, mpf_cmp, mpf_div, mpf_eq, mpf_floor,
+                     mpf_frac, mpf_frexp, mpf_ge, mpf_gt, mpf_hash, mpf_hypot,
+                     mpf_le, mpf_lt, mpf_mod, mpf_mul, mpf_mul_int, mpf_neg,
+                     mpf_nint, mpf_perturb, mpf_pos, mpf_pow_int, mpf_rand,
+                     mpf_rdiv_int, mpf_shift, mpf_sign, mpf_sqrt, mpf_sub,
+                     mpf_sum, normalize, prec_to_dps, repr_dps, round_ceiling,
+                     round_down, round_floor, round_int, round_nearest,
+                     round_up, str_to_man_exp, to_digits_exp, to_fixed,
+                     to_float, to_int, to_man_exp, to_pickable, to_rational,
+                     to_str)
+from .libmpi import (mpci_abs, mpci_add, mpci_cos, mpci_div, mpci_exp,
+                     mpci_factorial, mpci_gamma, mpci_log, mpci_loggamma,
+                     mpci_mul, mpci_neg, mpci_pos, mpci_pow, mpci_rgamma,
+                     mpci_sin, mpci_sub, mpi_abs, mpi_add, mpi_atan, mpi_atan2,
+                     mpi_cos, mpi_cos_sin, mpi_cot, mpi_delta, mpi_div, mpi_eq,
+                     mpi_exp, mpi_factorial, mpi_from_str, mpi_gamma, mpi_ge,
+                     mpi_gt, mpi_le, mpi_log, mpi_loggamma, mpi_lt, mpi_mid,
+                     mpi_mul, mpi_ne, mpi_neg, mpi_pos, mpi_pow, mpi_pow_int,
+                     mpi_rgamma, mpi_sin, mpi_sqrt, mpi_str, mpi_sub, mpi_tan,
+                     mpi_to_str)
diff --git a/mpmath/libmp/libintmath.py b/mpmath/libmp/libintmath.py
index 2e5d6ea..e2c7da7 100644
--- a/mpmath/libmp/libintmath.py
+++ b/mpmath/libmp/libintmath.py
@@ -113,7 +113,7 @@ def sage_trailing(n):
 
 def bin_to_radix(x, xbits, base, bdigits):
     """Changes radix of a fixed-point number; i.e., converts
-    x * 2**xbits to floor(x * 10**bdigits)."""
+    x * 2**xbits to floor(x * base**bdigits)."""
     return x * (MPZ(base)**bdigits) >> xbits
 
 stddigits = '0123456789abcdefghijklmnopqrstuvwxyz'
diff --git a/mpmath/libmp/libmpf.py b/mpmath/libmp/libmpf.py
index 09ff9fc..ac2b78a 100644
--- a/mpmath/libmp/libmpf.py
+++ b/mpmath/libmp/libmpf.py
@@ -3,22 +3,20 @@
 """
 
 import math
-
+import sys
 from bisect import bisect
 
-import sys
 
 # Importing random is slow
 #from random import getrandbits
 getrandbits = None
 
-from .backend import (MPZ, MPZ_ZERO, MPZ_ONE, MPZ_TWO, MPZ_FIVE,
-    BACKEND, STRICT, HASH_MODULUS, HASH_BITS, gmpy, sage, sage_utils)
+from .backend import (BACKEND, HASH_BITS, HASH_MODULUS, MPZ, MPZ_FIVE, MPZ_ONE,
+                      MPZ_TWO, MPZ_ZERO, STRICT, gmpy, sage, sage_utils)
+from .libintmath import (bctable, bin_to_radix, bitcount, giant_steps, isqrt,
+                         isqrt_fast, lshift, numeral, rshift, sqrt_fixed,
+                         sqrtrem, trailing, trailtable)
 
-from .libintmath import (giant_steps,
-    trailtable, bctable, lshift, rshift, bitcount, trailing,
-    sqrt_fixed, numeral, isqrt, isqrt_fast, sqrtrem,
-    bin_to_radix)
 
 # We don't pickle tuples directly for the following reasons:
 #   1: pickle uses str() for ints, which is inefficient when they are large
@@ -1072,6 +1070,7 @@ def to_digits_exp(s, dps):
     exp_from_1 = exp + bc
     if abs(exp_from_1) > 3500:
         from .libelefun import mpf_ln2, mpf_ln10
+
         # Set b = int(exp * log(2)/log(10))
         # If exp is huge, we must use high-precision arithmetic to
         # find the nearest power of ten
@@ -1186,10 +1185,14 @@ def to_str(s, dps, strip_zeros=True, min_fixed=None, max_fixed=None,
 def str_to_man_exp(x, base=10):
     """Helper function for from_str."""
     x = x.lower().rstrip('l').replace('_', '')
-    # Verify that the input is a valid float literal
-    float(x)
     # Split into mantissa, exponent
-    parts = x.split('e')
+    if base <= 10:
+        sep = 'e'
+    else:
+        sep = '@'
+    if pow(2, e2 := int(math.log2(base))) == base and e2 in [1, 4] and x.find('p') >= 0:
+        sep = 'p'
+    parts = x.split(sep)
     if len(parts) == 1:
         exp = 0
     else: # == 2
@@ -1199,7 +1202,10 @@ def str_to_man_exp(x, base=10):
     parts = x.split('.')
     if len(parts) == 2:
         a, b = parts[0], parts[1].rstrip('0')
-        exp -= len(b)
+        if sep != 'p':
+            exp -= len(b)
+        else:
+            exp -= len(b)*e2
         if a == '':
             a = '0'
         x = a + b
@@ -1208,12 +1214,12 @@ def str_to_man_exp(x, base=10):
 
 special_str = {'inf':finf, '+inf':finf, '-inf':fninf, 'nan':fnan}
 
-def from_str(x, prec, rnd=round_fast):
-    """Create a raw mpf from a decimal literal, rounding in the
+def from_str(x, prec=0, rnd=round_fast, base=0):
+    """Create a raw mpf from a string x in a given base, rounding in the
     specified direction if the input number cannot be represented
     exactly as a binary floating-point number with the given number of
-    bits. The literal syntax accepted is the same as for Python
-    floats.
+    bits.  The string syntax accepted for float() or float.fromhex()
+    is accepted too.
 
     TODO: the rounding does not work properly for large exponents.
     """
@@ -1221,42 +1227,43 @@ def from_str(x, prec, rnd=round_fast):
     if x in special_str:
         return special_str[x]
 
+    if not base:
+        if x.startswith(('0b', '-0b', '0B', '-0B')):
+            base = 2
+        elif x.startswith(('0x', '-0x', '0X', '-0X')):
+            base = 16
+        elif x.startswith(('0o', '-0o')):
+            base = 8
+        else:
+            base = 10
+
     if '/' in x:
         p, q = x.split('/')
         p, q = p.rstrip('l'), q.rstrip('l')
-        return from_rational(int(p), int(q), prec, rnd)
+        return from_rational(int(p, base), int(q, base), prec, rnd)
 
-    man, exp = str_to_man_exp(x, base=10)
+    man, exp = str_to_man_exp(x, base)
 
-    # XXX: appropriate cutoffs & track direction
-    # note no factors of 5
-    if abs(exp) > 400:
-        s = from_int(man, prec+10)
-        s = mpf_mul(s, mpf_pow_int(ften, exp, prec+10), prec, rnd)
-    else:
-        if exp >= 0:
-            s = from_int(man * 10**exp, prec, rnd)
+    if base == 10:
+        # XXX: appropriate cutoffs & track direction
+        # note no factors of 5
+        if abs(exp) > 400:
+            s = from_int(man, prec+10)
+            s = mpf_mul(s, mpf_pow_int(ften, exp, prec+10), prec, rnd)
+        else:
+            if exp >= 0:
+                s = from_int(man * 10**exp, prec, rnd)
+            else:
+                s = from_rational(man, 10**-exp, prec, rnd)
+    elif pow(2, e2 := int(math.log2(base))) == base:
+        if x.find('p') < 0:
+            s = from_man_exp(man, exp*e2, prec, rnd)
         else:
-            s = from_rational(man, 10**-exp, prec, rnd)
+            s = from_man_exp(man, exp, prec, rnd)
+    else:
+        raise NotImplementedError
     return s
 
-# Binary string conversion. These are currently mainly used for debugging
-# and could use some improvement in the future
-
-def from_bstr(x):
-    man, exp = str_to_man_exp(x, base=2)
-    man = MPZ(man)
-    sign = 0
-    if man < 0:
-        man = -man
-        sign = 1
-    bc = bitcount(man)
-    return normalize(sign, man, exp, bc, bc, round_floor)
-
-def to_bstr(x):
-    sign, man, exp, bc = x
-    return ['','-'][sign] + numeral(man, size=bitcount(man), base=2) + ("e%i" % exp)
-
 
 #----------------------------------------------------------------------------#
 #                                Square roots                                #


Test patch:
diff --git a/mpmath/tests/test_basic_ops.py b/mpmath/tests/test_basic_ops.py
index 3b4f6ef..356e32f 100644
--- a/mpmath/tests/test_basic_ops.py
+++ b/mpmath/tests/test_basic_ops.py
@@ -491,3 +491,8 @@ def test_ctx_mag():
     assert mp.mag(MPQ(1, 2)) == 0
     assert mp.mag(MPQ(2)) == 2
     assert mp.mag(MPQ(0)) == mpf('-inf')
+
+
+def test_ctx_mp_mpnumeric():
+    with pytest.deprecated_call():
+        from mpmath.ctx_mp import mpnumeric
diff --git a/mpmath/tests/test_convert.py b/mpmath/tests/test_convert.py
index 6abf2aa..8b2205a 100644
--- a/mpmath/tests/test_convert.py
+++ b/mpmath/tests/test_convert.py
@@ -52,6 +52,15 @@ def test_basic_string():
     assert to_str(from_str('1.0_0', 80), 24) == '1.0'
     assert to_str(from_str('.000', 80), 24) == '0.0'
 
+def test_from_str():
+    assert mpf(from_str('ABC.ABC', base=16)) == mpf(float.fromhex('ABC.ABC'))
+    assert mpf(from_str('0xABC.ABC')) == mpf(float.fromhex('ABC.ABC'))
+    assert mpf(from_str('0x3.a7p10')) == mpf(float.fromhex('0x3.a7p10'))
+    assert mpf(from_str('0x1.4ace478p+33')) == mpf(float.fromhex('0x1.4ace478p+33'))
+    assert mpf(from_str('0x1.4ace478@+33')) == mpf('7.0354608312666732e+39')
+    assert mpf(from_str('0b1101.100101')) == mpf('13.578125')
+    assert mpf(from_str('0o1101.100101')) == mpf('577.12524795532227')
+
 def test_pretty():
     mp.pretty = True
     assert repr(mpf(2.5)) == '2.5'
diff --git a/mpmath/tests/test_division.py b/mpmath/tests/test_division.py
index 3b0ea52..d298be0 100644
--- a/mpmath/tests/test_division.py
+++ b/mpmath/tests/test_division.py
@@ -1,79 +1,74 @@
 from random import choice, randint, seed
 
 from mpmath import mpf
-from mpmath.libmp import *
-
-
-all_modes = [round_floor, round_ceiling, round_down, round_up, round_nearest]
-
-fb = from_bstr
-fi = from_int
-ff = from_float
+from mpmath.libmp import (bitcount, from_int, from_str, mpf_div, mpf_mul,
+                          mpf_rdiv_int, round_ceiling, round_down, round_floor,
+                          round_nearest, round_up, trailing)
 
 
 def test_div_1_3():
-    a = fi(1)
-    b = fi(3)
-    c = fi(-1)
+    a = from_int(1)
+    b = from_int(3)
+    c = from_int(-1)
 
     # floor rounds down, ceiling rounds up
-    assert mpf_div(a, b, 7, round_floor)   == fb('0.01010101')
-    assert mpf_div(a, b, 7, round_ceiling) == fb('0.01010110')
-    assert mpf_div(a, b, 7, round_down)    == fb('0.01010101')
-    assert mpf_div(a, b, 7, round_up)      == fb('0.01010110')
-    assert mpf_div(a, b, 7, round_nearest) == fb('0.01010101')
+    assert mpf_div(a, b, 7, round_floor)   == from_str('0.01010101', base=2)
+    assert mpf_div(a, b, 7, round_ceiling) == from_str('0.01010110', base=2)
+    assert mpf_div(a, b, 7, round_down)    == from_str('0.01010101', base=2)
+    assert mpf_div(a, b, 7, round_up)      == from_str('0.01010110', base=2)
+    assert mpf_div(a, b, 7, round_nearest) == from_str('0.01010101', base=2)
 
     # floor rounds up, ceiling rounds down
-    assert mpf_div(c, b, 7, round_floor)   == fb('-0.01010110')
-    assert mpf_div(c, b, 7, round_ceiling) == fb('-0.01010101')
-    assert mpf_div(c, b, 7, round_down)    == fb('-0.01010101')
-    assert mpf_div(c, b, 7, round_up)      == fb('-0.01010110')
-    assert mpf_div(c, b, 7, round_nearest) == fb('-0.01010101')
+    assert mpf_div(c, b, 7, round_floor)   == from_str('-0.01010110', base=2)
+    assert mpf_div(c, b, 7, round_ceiling) == from_str('-0.01010101', base=2)
+    assert mpf_div(c, b, 7, round_down)    == from_str('-0.01010101', base=2)
+    assert mpf_div(c, b, 7, round_up)      == from_str('-0.01010110', base=2)
+    assert mpf_div(c, b, 7, round_nearest) == from_str('-0.01010101', base=2)
 
 def test_mpf_divi_1_3():
     a = 1
-    b = fi(3)
+    b = from_int(3)
     c = -1
-    assert mpf_rdiv_int(a, b, 7, round_floor)   == fb('0.01010101')
-    assert mpf_rdiv_int(a, b, 7, round_ceiling) == fb('0.01010110')
-    assert mpf_rdiv_int(a, b, 7, round_down)    == fb('0.01010101')
-    assert mpf_rdiv_int(a, b, 7, round_up)      == fb('0.01010110')
-    assert mpf_rdiv_int(a, b, 7, round_nearest) == fb('0.01010101')
-    assert mpf_rdiv_int(c, b, 7, round_floor)   == fb('-0.01010110')
-    assert mpf_rdiv_int(c, b, 7, round_ceiling) == fb('-0.01010101')
-    assert mpf_rdiv_int(c, b, 7, round_down)    == fb('-0.01010101')
-    assert mpf_rdiv_int(c, b, 7, round_up)      == fb('-0.01010110')
-    assert mpf_rdiv_int(c, b, 7, round_nearest) == fb('-0.01010101')
+    assert mpf_rdiv_int(a, b, 7, round_floor)   == from_str('0.01010101', base=2)
+    assert mpf_rdiv_int(a, b, 7, round_ceiling) == from_str('0.01010110', base=2)
+    assert mpf_rdiv_int(a, b, 7, round_down)    == from_str('0.01010101', base=2)
+    assert mpf_rdiv_int(a, b, 7, round_up)      == from_str('0.01010110', base=2)
+    assert mpf_rdiv_int(a, b, 7, round_nearest) == from_str('0.01010101', base=2)
+    assert mpf_rdiv_int(c, b, 7, round_floor)   == from_str('-0.01010110', base=2)
+    assert mpf_rdiv_int(c, b, 7, round_ceiling) == from_str('-0.01010101', base=2)
+    assert mpf_rdiv_int(c, b, 7, round_down)    == from_str('-0.01010101', base=2)
+    assert mpf_rdiv_int(c, b, 7, round_up)      == from_str('-0.01010110', base=2)
+    assert mpf_rdiv_int(c, b, 7, round_nearest) == from_str('-0.01010101', base=2)
 
 
 def test_div_300():
 
-    q = fi(1000000)
-    a = fi(300499999)    # a/q is a little less than a half-integer
-    b = fi(300500000)    # b/q exactly a half-integer
-    c = fi(300500001)    # c/q is a little more than a half-integer
+    q = from_int(1000000)
+    a = from_int(300499999)    # a/q is a little less than a half-integer
+    b = from_int(300500000)    # b/q exactly a half-integer
+    c = from_int(300500001)    # c/q is a little more than a half-integer
 
     # Check nearest integer rounding (prec=9 as 2**8 < 300 < 2**9)
 
-    assert mpf_div(a, q, 9, round_down) == fi(300)
-    assert mpf_div(b, q, 9, round_down) == fi(300)
-    assert mpf_div(c, q, 9, round_down) == fi(300)
-    assert mpf_div(a, q, 9, round_up) == fi(301)
-    assert mpf_div(b, q, 9, round_up) == fi(301)
-    assert mpf_div(c, q, 9, round_up) == fi(301)
+    assert mpf_div(a, q, 9, round_down) == from_int(300)
+    assert mpf_div(b, q, 9, round_down) == from_int(300)
+    assert mpf_div(c, q, 9, round_down) == from_int(300)
+    assert mpf_div(a, q, 9, round_up) == from_int(301)
+    assert mpf_div(b, q, 9, round_up) == from_int(301)
+    assert mpf_div(c, q, 9, round_up) == from_int(301)
 
     # Nearest even integer is down
-    assert mpf_div(a, q, 9, round_nearest) == fi(300)
-    assert mpf_div(b, q, 9, round_nearest) == fi(300)
-    assert mpf_div(c, q, 9, round_nearest) == fi(301)
+    assert mpf_div(a, q, 9, round_nearest) == from_int(300)
+    assert mpf_div(b, q, 9, round_nearest) == from_int(300)
+    assert mpf_div(c, q, 9, round_nearest) == from_int(301)
 
     # Nearest even integer is up
-    a = fi(301499999)
-    b = fi(301500000)
-    c = fi(301500001)
-    assert mpf_div(a, q, 9, round_nearest) == fi(301)
-    assert mpf_div(b, q, 9, round_nearest) == fi(302)
-    assert mpf_div(c, q, 9, round_nearest) == fi(302)
+    a = from_int(301499999)
+    b = from_int(301500000)
+    c = from_int(301500001)
+    assert mpf_div(a, q, 9, round_nearest) == from_int(301)
+    assert mpf_div(b, q, 9, round_nearest) == from_int(302)
+    assert mpf_div(c, q, 9, round_nearest) == from_int(302)
 
 
 def test_tight_integer_division():
@@ -85,8 +80,9 @@ def test_tight_integer_division():
         b = choice([1, -1]) * randint(1, 1<<randint(10, 100))
         p = a * b
         width = bitcount(abs(b)) - trailing(b)
-        a = fi(a); b = fi(b); p = fi(p)
-        for mode in all_modes:
+        a = from_int(a); b = from_int(b); p = from_int(p)
+        for mode in [round_floor, round_ceiling, round_down,
+                     round_up, round_nearest]:
             assert mpf_div(p, a, width, mode) == b
 
 
@@ -94,34 +90,34 @@ def test_epsilon_rounding():
     # Verify that mpf_div uses infinite precision; this result will
     # appear to be exactly 0.101 to a near-sighted algorithm
 
-    a = fb('0.101' + ('0'*200) + '1')
-    b = fb('1.10101')
+    a = from_str('0.101' + ('0'*200) + '1', base=2)
+    b = from_str('1.10101', base=2)
     c = mpf_mul(a, b, 250, round_floor) # exact
     assert mpf_div(c, b, bitcount(a[1]), round_floor) == a # exact
 
-    assert mpf_div(c, b, 2, round_down) == fb('0.10')
-    assert mpf_div(c, b, 3, round_down) == fb('0.101')
-    assert mpf_div(c, b, 2, round_up) == fb('0.11')
-    assert mpf_div(c, b, 3, round_up) == fb('0.110')
-    assert mpf_div(c, b, 2, round_floor) == fb('0.10')
-    assert mpf_div(c, b, 3, round_floor) == fb('0.101')
-    assert mpf_div(c, b, 2, round_ceiling) == fb('0.11')
-    assert mpf_div(c, b, 3, round_ceiling) == fb('0.110')
+    assert mpf_div(c, b, 2, round_down) == from_str('0.10', base=2)
+    assert mpf_div(c, b, 3, round_down) == from_str('0.101', base=2)
+    assert mpf_div(c, b, 2, round_up) == from_str('0.11', base=2)
+    assert mpf_div(c, b, 3, round_up) == from_str('0.110', base=2)
+    assert mpf_div(c, b, 2, round_floor) == from_str('0.10', base=2)
+    assert mpf_div(c, b, 3, round_floor) == from_str('0.101', base=2)
+    assert mpf_div(c, b, 2, round_ceiling) == from_str('0.11', base=2)
+    assert mpf_div(c, b, 3, round_ceiling) == from_str('0.110', base=2)
 
     # The same for negative numbers
-    a = fb('-0.101' + ('0'*200) + '1')
-    b = fb('1.10101')
+    a = from_str('-0.101' + ('0'*200) + '1', base=2)
+    b = from_str('1.10101', base=2)
     c = mpf_mul(a, b, 250, round_floor)
     assert mpf_div(c, b, bitcount(a[1]), round_floor) == a
 
-    assert mpf_div(c, b, 2, round_down) == fb('-0.10')
-    assert mpf_div(c, b, 3, round_up) == fb('-0.110')
+    assert mpf_div(c, b, 2, round_down) == from_str('-0.10', base=2)
+    assert mpf_div(c, b, 3, round_up) == from_str('-0.110', base=2)
 
     # Floor goes up, ceiling goes down
-    assert mpf_div(c, b, 2, round_floor) == fb('-0.11')
-    assert mpf_div(c, b, 3, round_floor) == fb('-0.110')
-    assert mpf_div(c, b, 2, round_ceiling) == fb('-0.10')
-    assert mpf_div(c, b, 3, round_ceiling) == fb('-0.101')
+    assert mpf_div(c, b, 2, round_floor) == from_str('-0.11', base=2)
+    assert mpf_div(c, b, 3, round_floor) == from_str('-0.110', base=2)
+    assert mpf_div(c, b, 2, round_ceiling) == from_str('-0.10', base=2)
+    assert mpf_div(c, b, 3, round_ceiling) == from_str('-0.101', base=2)
 
 
 def test_mod():
diff --git a/mpmath/tests/test_functions2.py b/mpmath/tests/test_functions2.py
index 3a1ce92..89cbe6e 100644
--- a/mpmath/tests/test_functions2.py
+++ b/mpmath/tests/test_functions2.py
@@ -1352,8 +1352,10 @@ def test_hyper_param_accuracy():
     assert hyp2f1(-5, 10, 3, 0.5, zeroprec=500) == 0
     assert (hyp1f1(-10000, 1000, 100)*10**424).ae(-3.1046080515824859974)
     assert (hyp2f1(1000,1.5,-3.5,-0.75,maxterms=100000)*10**231).ae(-4.0534790813913998643)
+    assert (hyp2f1(1000,1.5,-3.5,-0.75,maxterms=10000)*10**231).ae(-4.0534790813913998643)
+    pytest.raises(mp.NoConvergence, lambda: hyp2f1(1000,1.5,-3.5,-0.75,maxterms=10000,force_series=True))
     assert legenp(2, 3, 0.25) == 0
-    pytest.raises(ValueError, lambda: hypercomb(lambda a: [([],[],[],[],[a],[-a],0.5)], [3]))
+    pytest.raises(mp.NoConvergence, lambda: hypercomb(lambda a: [([],[],[],[],[a],[-a],0.5)], [3]))
     assert hypercomb(lambda a: [([],[],[],[],[a],[-a],0.5)], [3], infprec=200) == inf
     assert meijerg([[],[]],[[0,0,0,0],[]],0.1).ae(1.5680822343832351418)
     assert (besselk(400,400)*10**94).ae(1.4387057277018550583)