Files
Sergey B Kirpichev 0e1bd9496d Restrict libmp exports to public API
This is following namespace:
```
{'BACKEND', 'ComplexResult', 'MPZ', 'MPZ_ONE', 'NoConvergence',
 'catalan_fixed', 'dps_to_prec', 'euler_fixed', 'fhalf', 'finf',
 'fnan', 'fninf', 'fnone', 'fone', 'from_float', 'from_int', 'from_man_exp',
 'from_rational', 'from_str', 'fzero', 'giant_steps', 'ifac', 'ifib',
 'int_types', 'isqrt', 'mpc_abs', 'mpc_exp', 'mpc_pow', 'mpc_pow_int',
 'mpc_pow_mpf', 'mpc_sqrt', 'mpf_abs', 'mpf_add', 'mpf_atan', 'mpf_atan2',
 'mpf_bernoulli', 'mpf_ceil', 'mpf_cmp', 'mpf_cos', 'mpf_cosh_sinh', 'mpf_div',
 'mpf_e', 'mpf_eq', 'mpf_exp', 'mpf_floor', 'mpf_ge', 'mpf_gt', 'mpf_le',
 'mpf_log', 'mpf_lt', 'mpf_mod', 'mpf_mul', 'mpf_neg', 'mpf_pi', 'mpf_pow',
 'mpf_pow_int', 'mpf_shift', 'mpf_sign', 'mpf_sin', 'mpf_sqrt', 'mpf_sub',
 'mpf_tan', 'normalize', 'phi_fixed', 'prec_to_dps', 'repr_dps',
 'round_nearest', 'sqrtrem', 'to_float', 'to_int', 'to_man_exp', 'to_rational',
 'to_str'}
```

Closes #704
2026-05-25 08:31:19 +03:00

184 lines
7.8 KiB
Python

"""
Test bit-level integer and mpf operations
"""
from mpmath import eps, fadd, ldexp, mp, mpc, mpf
from mpmath.libmp import (MPZ, fone, from_float, from_man_exp, fzero, mpf_add,
mpf_neg, mpf_sub, round_ceiling, round_down,
round_floor, round_nearest, round_up, to_float)
from mpmath.libmp.libintmath import trailing
from mpmath.libmp.libmpf import mpf_perturb
def test_trailing():
assert trailing(0) == 0
assert trailing(1) == 0
assert trailing(2) == 1
assert trailing(7) == 0
assert trailing(8) == 3
assert trailing(2**100) == 100
assert trailing(2**100-1) == 0
def test_round_down():
assert from_man_exp(MPZ(0), -4, 4, round_down)[:3] == (0, 0, 0)
assert from_man_exp(MPZ(0xf0), -4, 4, round_down)[:3] == (0, 15, 0)
assert from_man_exp(MPZ(0xf1), -4, 4, round_down)[:3] == (0, 15, 0)
assert from_man_exp(MPZ(0xff), -4, 4, round_down)[:3] == (0, 15, 0)
assert from_man_exp(MPZ(-0xf0), -4, 4, round_down)[:3] == (1, 15, 0)
assert from_man_exp(MPZ(-0xf1), -4, 4, round_down)[:3] == (1, 15, 0)
assert from_man_exp(MPZ(-0xff), -4, 4, round_down)[:3] == (1, 15, 0)
def test_round_up():
assert from_man_exp(MPZ(0), -4, 4, round_up)[:3] == (0, 0, 0)
assert from_man_exp(MPZ(0xf0), -4, 4, round_up)[:3] == (0, 15, 0)
assert from_man_exp(MPZ(0xf1), -4, 4, round_up)[:3] == (0, 1, 4)
assert from_man_exp(MPZ(0xff), -4, 4, round_up)[:3] == (0, 1, 4)
assert from_man_exp(MPZ(-0xf0), -4, 4, round_up)[:3] == (1, 15, 0)
assert from_man_exp(MPZ(-0xf1), -4, 4, round_up)[:3] == (1, 1, 4)
assert from_man_exp(MPZ(-0xff), -4, 4, round_up)[:3] == (1, 1, 4)
def test_round_floor():
assert from_man_exp(MPZ(0), -4, 4, round_floor)[:3] == (0, 0, 0)
assert from_man_exp(MPZ(0xf0), -4, 4, round_floor)[:3] == (0, 15, 0)
assert from_man_exp(MPZ(0xf1), -4, 4, round_floor)[:3] == (0, 15, 0)
assert from_man_exp(MPZ(0xff), -4, 4, round_floor)[:3] == (0, 15, 0)
assert from_man_exp(MPZ(-0xf0), -4, 4, round_floor)[:3] == (1, 15, 0)
assert from_man_exp(MPZ(-0xf1), -4, 4, round_floor)[:3] == (1, 1, 4)
assert from_man_exp(MPZ(-0xff), -4, 4, round_floor)[:3] == (1, 1, 4)
def test_round_ceiling():
assert from_man_exp(MPZ(0), -4, 4, round_ceiling)[:3] == (0, 0, 0)
assert from_man_exp(MPZ(0xf0), -4, 4, round_ceiling)[:3] == (0, 15, 0)
assert from_man_exp(MPZ(0xf1), -4, 4, round_ceiling)[:3] == (0, 1, 4)
assert from_man_exp(MPZ(0xff), -4, 4, round_ceiling)[:3] == (0, 1, 4)
assert from_man_exp(MPZ(-0xf0), -4, 4, round_ceiling)[:3] == (1, 15, 0)
assert from_man_exp(MPZ(-0xf1), -4, 4, round_ceiling)[:3] == (1, 15, 0)
assert from_man_exp(MPZ(-0xff), -4, 4, round_ceiling)[:3] == (1, 15, 0)
def test_round_nearest():
assert from_man_exp(MPZ(0), -4, 4, round_nearest)[:3] == (0, 0, 0)
assert from_man_exp(MPZ(0xf0), -4, 4, round_nearest)[:3] == (0, 15, 0)
assert from_man_exp(MPZ(0xf7), -4, 4, round_nearest)[:3] == (0, 15, 0)
assert from_man_exp(MPZ(0xf8), -4, 4, round_nearest)[:3] == (0, 1, 4) # 1111.1000 -> 10000.0
assert from_man_exp(MPZ(0xf9), -4, 4, round_nearest)[:3] == (0, 1, 4) # 1111.1001 -> 10000.0
assert from_man_exp(MPZ(0xe8), -4, 4, round_nearest)[:3] == (0, 7, 1) # 1110.1000 -> 1110.0
assert from_man_exp(MPZ(0xe9), -4, 4, round_nearest)[:3] == (0, 15, 0) # 1110.1001 -> 1111.0
assert from_man_exp(MPZ(-0xf0), -4, 4, round_nearest)[:3] == (1, 15, 0)
assert from_man_exp(MPZ(-0xf7), -4, 4, round_nearest)[:3] == (1, 15, 0)
assert from_man_exp(MPZ(-0xf8), -4, 4, round_nearest)[:3] == (1, 1, 4)
assert from_man_exp(MPZ(-0xf9), -4, 4, round_nearest)[:3] == (1, 1, 4)
assert from_man_exp(MPZ(-0xe8), -4, 4, round_nearest)[:3] == (1, 7, 1)
assert from_man_exp(MPZ(-0xe9), -4, 4, round_nearest)[:3] == (1, 15, 0)
def test_rounding_bugs():
# 1 less than power-of-two cases
assert from_man_exp(MPZ(72057594037927935), -56, 53, round_up)[:3] == (0, 1, 0)
assert from_man_exp(MPZ(73786976294838205979), -65, 53, round_nearest)[:3] == (0, 1, 1)
assert from_man_exp(MPZ(31), 0, 4, round_up)[:3] == (0, 1, 5)
assert from_man_exp(MPZ(-31), 0, 4, round_floor)[:3] == (1, 1, 5)
assert from_man_exp(MPZ(255), 0, 7, round_up)[:3] == (0, 1, 8)
assert from_man_exp(MPZ(-255), 0, 7, round_floor)[:3] == (1, 1, 8)
def test_rounding_issue_200():
a = from_man_exp(MPZ(9867),-100)
b = from_man_exp(MPZ(9867),-200)
c = from_man_exp(MPZ(-1),0)
z = (1, 1023, -10)
assert mpf_add(a, c, 10, 'd')[:3] == z
assert mpf_add(b, c, 10, 'd')[:3] == z
assert mpf_add(c, a, 10, 'd')[:3] == z
assert mpf_add(c, b, 10, 'd')[:3] == z
def test_perturb():
a = fone
b = from_float(0.99999999999999989)
c = from_float(1.0000000000000002)
assert mpf_perturb(a, 0, 53, round_nearest) == a
assert mpf_perturb(a, 1, 53, round_nearest) == a
assert mpf_perturb(a, 0, 53, round_up) == c
assert mpf_perturb(a, 0, 53, round_ceiling) == c
assert mpf_perturb(a, 0, 53, round_down) == a
assert mpf_perturb(a, 0, 53, round_floor) == a
assert mpf_perturb(a, 1, 53, round_up) == a
assert mpf_perturb(a, 1, 53, round_ceiling) == a
assert mpf_perturb(a, 1, 53, round_down) == b
assert mpf_perturb(a, 1, 53, round_floor) == b
a = mpf_neg(a)
b = mpf_neg(b)
c = mpf_neg(c)
assert mpf_perturb(a, 0, 53, round_nearest) == a
assert mpf_perturb(a, 1, 53, round_nearest) == a
assert mpf_perturb(a, 0, 53, round_up) == a
assert mpf_perturb(a, 0, 53, round_floor) == a
assert mpf_perturb(a, 0, 53, round_down) == b
assert mpf_perturb(a, 0, 53, round_ceiling) == b
assert mpf_perturb(a, 1, 53, round_up) == c
assert mpf_perturb(a, 1, 53, round_floor) == c
assert mpf_perturb(a, 1, 53, round_down) == a
assert mpf_perturb(a, 1, 53, round_ceiling) == a
def test_add_exact():
ff = from_float
assert mpf_add(ff(3.0), ff(2.5)) == ff(5.5)
assert mpf_add(ff(3.0), ff(-2.5)) == ff(0.5)
assert mpf_add(ff(-3.0), ff(2.5)) == ff(-0.5)
assert mpf_add(ff(-3.0), ff(-2.5)) == ff(-5.5)
assert mpf_sub(mpf_add(fone, ff(1e-100)), fone) == ff(1e-100)
assert mpf_sub(mpf_add(ff(1e-100), fone), fone) == ff(1e-100)
assert mpf_sub(mpf_add(fone, ff(-1e-100)), fone) == ff(-1e-100)
assert mpf_sub(mpf_add(ff(-1e-100), fone), fone) == ff(-1e-100)
assert mpf_add(fone, fzero) == fone
assert mpf_add(fzero, fone) == fone
assert mpf_add(fzero, fzero) == fzero
def test_long_exponent_shifts():
# Check for possible bugs due to exponent arithmetic overflow
# in a C implementation
x = mpf(1)
for p in [32, 64]:
a = ldexp(1,2**(p-1))
b = ldexp(1,2**p)
c = ldexp(1,2**(p+1))
d = ldexp(1,-2**(p-1))
e = ldexp(1,-2**p)
f = ldexp(1,-2**(p+1))
assert (x+a) == a
assert (x+b) == b
assert (x+c) == c
assert (x+d) == x
assert (x+e) == x
assert (x+f) == x
assert (a+x) == a
assert (b+x) == b
assert (c+x) == c
assert (d+x) == x
assert (e+x) == x
assert (f+x) == x
assert (x-a) == -a
assert (x-b) == -b
assert (x-c) == -c
assert (x-d) == x
assert (x-e) == x
assert (x-f) == x
assert (a-x) == a
assert (b-x) == b
assert (c-x) == c
assert (d-x) == -x
assert (e-x) == -x
assert (f-x) == -x
def test_float_rounding():
mp.prec = 64
for x in [mpf(1), mpf(1)+eps, mpf(1)-eps, -mpf(1)+eps, -mpf(1)-eps]:
fa = float(x)
fb = float(fadd(x,0,prec=53,rounding='n'))
assert fa == fb
z = mpc(x,x)
ca = complex(z)
cb = complex(fadd(z,0,prec=53,rounding='n'))
assert ca == cb
for rnd in ['n', 'd', 'u', 'f', 'c']:
fa = to_float(x._mpf_, rnd=rnd)
fb = to_float(fadd(x,0,prec=53,rounding=rnd)._mpf_, rnd=rnd)
assert fa == fb