Revert "Add isspecial() method for mp/fp contexts, deprecate isnormal()"
This reverts commit e6aa3b46b1.
Subnormals are properly handled by fp.isnormal(). Deprecate
fp.is_special() method.
Fixes #946
This commit is contained in:
@@ -58,7 +58,6 @@ Features:
|
||||
#936 (Sergey B Kirpichev)
|
||||
* Use PyREPL, as fallback (no IPython), see #941 (Sergey B Kirpichev)
|
||||
* Add exp2() and log2(), see #948 (Sergey B Kirpichev)
|
||||
* Add isspecial() method for contexts, see #949 (Sergey B Kirpichev)
|
||||
* Support rounding property for the mp context, see #963 (Sergey B Kirpichev)
|
||||
* Add Fox H-function with rational A/B parameters (foxh()), see #982 (Hongren Zheng)
|
||||
|
||||
@@ -79,13 +78,13 @@ Compatibility:
|
||||
#779, #844 and #845 (Sergey B Kirpichev, Warren Weckesser)
|
||||
* Deprecate mpmath.math2, see #769 (Sergey B Kirpichev)
|
||||
* Drop support for CPython 3.8, see #911 (Sergey B Kirpichev)
|
||||
* Deprecate isnormal() method of contexts, see #949 (Sergey B Kirpichev)
|
||||
* Importing from the mpmath.libmp submodules is deprecated, use instead ``from
|
||||
mpmath.libmp import foo``, see
|
||||
issue https://github.com/mpmath/mpmath/issues/704#issuecomment-2953536980
|
||||
for available functions (Sergey B Kirpichev)
|
||||
* Deprecate bitcount function, see #721 and #955 (Sergey B Kirpichev)
|
||||
* Deprecate mpf/mpc_log, see #989 (Sergey B Kirpichev)
|
||||
* Deprecate fp.is_special(), see #1042 (Sergey B Kirpichev)
|
||||
|
||||
Bug fixes:
|
||||
|
||||
@@ -168,6 +167,7 @@ Bug fixes:
|
||||
* Fix erf(z) with re(z) of large magnitude, see #1039 (Sergey B Kirpichev)
|
||||
* Return nan's for polylog(s, nan) or polylog(s, nan+nanj),
|
||||
see #1041 (Sergey B Kirpichev)
|
||||
* Fix fp.isnormal() for subnormals, see #1042 (Sergey B Kirpichev)
|
||||
|
||||
Maintenance:
|
||||
|
||||
|
||||
@@ -75,7 +75,6 @@ multiplicity = mp.multiplicity
|
||||
isinf = mp.isinf
|
||||
isnan = mp.isnan
|
||||
isnormal = mp.isnormal
|
||||
isspecial = mp.isspecial
|
||||
isint = mp.isint
|
||||
isfinite = mp.isfinite
|
||||
almosteq = mp.almosteq
|
||||
|
||||
+9
-8
@@ -2,8 +2,8 @@ import cmath
|
||||
import functools
|
||||
import inspect
|
||||
import math
|
||||
import sys
|
||||
import warnings
|
||||
import sys
|
||||
|
||||
from . import function_docs, libfp, libmp
|
||||
from .ctx_base import StandardBaseContext
|
||||
@@ -88,8 +88,10 @@ class FPContext(StandardBaseContext):
|
||||
|
||||
absmin = absmax = abs
|
||||
|
||||
def isspecial(ctx, x):
|
||||
return not x or x - x != 0.0
|
||||
def is_special(ctx, x):
|
||||
warnings.warn("the is_special() method is deprecated",
|
||||
DeprecationWarning)
|
||||
return not ctx.isnormal(x)
|
||||
|
||||
def isnan(ctx, x):
|
||||
return x != x
|
||||
@@ -103,11 +105,10 @@ class FPContext(StandardBaseContext):
|
||||
return math.isfinite(x)
|
||||
|
||||
def isnormal(ctx, x):
|
||||
warnings.warn("the isnormal() method is deprecated",
|
||||
DeprecationWarning)
|
||||
if x:
|
||||
return x - x == 0.0
|
||||
return False
|
||||
if type(x) is complex:
|
||||
return ctx.isnormal(abs(x))
|
||||
# XXX: can use math.isnormal() on Python 3.15+
|
||||
return bool(x) and math.isfinite(x) and abs(x) >= sys.float_info.min
|
||||
|
||||
def isnpint(ctx, x):
|
||||
if type(x) is complex:
|
||||
|
||||
+23
-45
@@ -1,7 +1,6 @@
|
||||
import inspect
|
||||
import numbers
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
from . import function_docs
|
||||
from .libmp import (MPQ, MPZ, ComplexResult, dps_to_prec, finf, fnan, fninf,
|
||||
@@ -909,8 +908,29 @@ class PythonMPContext:
|
||||
return ctx.isinf(x)
|
||||
|
||||
def isnormal(ctx, x):
|
||||
warnings.warn("the isnormal() method is deprecated",
|
||||
DeprecationWarning)
|
||||
"""
|
||||
Determine whether *x* is "normal" in the sense of floating-point
|
||||
representation; that is, return *False* if *x* is zero, an
|
||||
infinity or NaN; otherwise return *True*. By extension, a
|
||||
complex number *x* is considered "normal" if its magnitude is
|
||||
normal::
|
||||
|
||||
>>> from mpmath import isnormal, inf, nan, mpc
|
||||
>>> isnormal(3)
|
||||
True
|
||||
>>> isnormal(0)
|
||||
False
|
||||
>>> isnormal(inf); isnormal(-inf); isnormal(nan)
|
||||
False
|
||||
False
|
||||
False
|
||||
>>> isnormal(0+0j)
|
||||
False
|
||||
>>> isnormal(0+3j)
|
||||
True
|
||||
>>> isnormal(mpc(2,nan))
|
||||
False
|
||||
"""
|
||||
if hasattr(x, "_mpf_"):
|
||||
if ctx.isfinite(x):
|
||||
return bool(to_man_exp(x._mpf_, signed=True)[0])
|
||||
@@ -927,48 +947,6 @@ class PythonMPContext:
|
||||
x = ctx.convert(x)
|
||||
return ctx.isnormal(x)
|
||||
|
||||
def isspecial(ctx, x):
|
||||
"""
|
||||
Determine whether *x* is a "special" in the sense of floating-point
|
||||
representation; that is, return *True* if *x* is zero, an
|
||||
infinity or NaN; otherwise return *False*. By extension, a
|
||||
complex number *x* is considered "special" if its magnitude is
|
||||
special::
|
||||
|
||||
>>> from mpmath import isspecial, inf, nan, mpc
|
||||
>>> isspecial(3)
|
||||
False
|
||||
>>> isspecial(0)
|
||||
True
|
||||
>>> isspecial(inf)
|
||||
True
|
||||
>>> isspecial(-inf)
|
||||
True
|
||||
>>> isspecial(nan)
|
||||
True
|
||||
>>> isspecial(0+0j)
|
||||
True
|
||||
>>> isspecial(0+3j)
|
||||
False
|
||||
>>> isspecial(mpc(2,nan))
|
||||
True
|
||||
"""
|
||||
if hasattr(x, "_mpf_"):
|
||||
if ctx.isfinite(x):
|
||||
return not bool(to_man_exp(x._mpf_, signed=True)[0])
|
||||
return True
|
||||
if hasattr(x, "_mpc_"):
|
||||
re, im = x._mpc_
|
||||
re_special = not bool(re[1])
|
||||
im_special = not bool(im[1])
|
||||
if re == fzero: return im_special
|
||||
if im == fzero: return re_special
|
||||
return re_special or im_special
|
||||
if isinstance(x, int_types) or isinstance(x, MPQ):
|
||||
return not bool(x)
|
||||
x = ctx.convert(x)
|
||||
return ctx.isspecial(x)
|
||||
|
||||
def isint(ctx, x, gaussian=False):
|
||||
"""
|
||||
Return *True* if *x* is integer-valued; otherwise return
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from ..libmp.backend import MPQ
|
||||
from .functions import defun, defun_wrapped
|
||||
|
||||
|
||||
@defun
|
||||
def j0(ctx, x):
|
||||
"""Computes the Bessel function `J_0(x)`. See :func:`~mpmath.besselj`."""
|
||||
@@ -513,7 +512,7 @@ def airyai(ctx, z, derivative=0, **kwargs):
|
||||
else:
|
||||
n = 0
|
||||
# Values at infinities
|
||||
if ctx.isspecial(z) and z:
|
||||
if not ctx.isnormal(z) and z:
|
||||
if n and ntype == 'Z':
|
||||
if n == -1:
|
||||
if z == ctx.inf:
|
||||
@@ -605,7 +604,7 @@ def airybi(ctx, z, derivative=0, **kwargs):
|
||||
else:
|
||||
n = 0
|
||||
# Values at infinities
|
||||
if ctx.isspecial(z) and z:
|
||||
if not ctx.isnormal(z) and z:
|
||||
if n and ntype == 'Z':
|
||||
if z == ctx.inf:
|
||||
return z
|
||||
|
||||
@@ -64,7 +64,6 @@ between the various parameters (:func:`~mpmath.qfrom`, :func:`~mpmath.mfrom`,
|
||||
|
||||
from .functions import defun, defun_wrapped
|
||||
|
||||
|
||||
@defun_wrapped
|
||||
def eta(ctx, tau):
|
||||
r"""
|
||||
@@ -480,7 +479,7 @@ def RF_calc(ctx, x, y, z, r):
|
||||
if y == z: return RC_calc(ctx, x, y, r)
|
||||
if x == z: return RC_calc(ctx, y, x, r)
|
||||
if x == y: return RC_calc(ctx, z, x, r)
|
||||
if ctx.isspecial(x) or ctx.isspecial(y) and ctx.isspecial(z):
|
||||
if not (ctx.isnormal(x) and ctx.isnormal(y) and ctx.isnormal(z)):
|
||||
if ctx.isnan(x) or ctx.isnan(y) or ctx.isnan(z):
|
||||
return x*y*z
|
||||
if ctx.isinf(x) or ctx.isinf(y) or ctx.isinf(z):
|
||||
@@ -510,7 +509,7 @@ def RF_calc(ctx, x, y, z, r):
|
||||
return ctx.power(Am,-0.5) * (9240-924*E2+385*E2**2+660*E3-630*E2*E3)/9240
|
||||
|
||||
def RC_calc(ctx, x, y, r, pv=True):
|
||||
if ctx.isspecial(x) or ctx.isspecial(y):
|
||||
if not (ctx.isnormal(x) and ctx.isnormal(y)):
|
||||
if ctx.isinf(x) or ctx.isinf(y):
|
||||
return 1/(x*y)
|
||||
if y == 0:
|
||||
@@ -550,8 +549,8 @@ def RJ_calc(ctx, x, y, z, p, r, integration):
|
||||
Carlson's algorithm is correct.
|
||||
With integration == 2, uses only integration.
|
||||
"""
|
||||
if (ctx.isspecial(x) or ctx.isspecial(y)
|
||||
or ctx.isspecial(z) or ctx.isspecial(p)):
|
||||
if not (ctx.isnormal(x) and ctx.isnormal(y) and \
|
||||
ctx.isnormal(z) and ctx.isnormal(p)):
|
||||
if ctx.isnan(x) or ctx.isnan(y) or ctx.isnan(z) or ctx.isnan(p):
|
||||
return x*y*z*p
|
||||
if ctx.isinf(x) or ctx.isinf(y) or ctx.isinf(z) or ctx.isinf(p):
|
||||
@@ -1132,7 +1131,7 @@ def ellipf(ctx, phi, m):
|
||||
|
||||
"""
|
||||
z = phi
|
||||
if ctx.isspecial(z) or ctx.isspecial(m):
|
||||
if not (ctx.isnormal(z) and ctx.isnormal(m)):
|
||||
if m == 0:
|
||||
return z + m
|
||||
if z == 0:
|
||||
@@ -1302,7 +1301,7 @@ def ellipe(ctx, *args):
|
||||
else:
|
||||
phi, m = args
|
||||
z = phi
|
||||
if ctx.isspecial(z) or ctx.isspecial(m):
|
||||
if not (ctx.isnormal(z) and ctx.isnormal(m)):
|
||||
if m == 0:
|
||||
return z + m
|
||||
if z == 0:
|
||||
@@ -1439,7 +1438,7 @@ def ellippi(ctx, *args):
|
||||
n, phi, m = args
|
||||
complete = False
|
||||
z = phi
|
||||
if ctx.isspecial(n) or ctx.isspecial(z) or ctx.isspecial(m):
|
||||
if not (ctx.isnormal(n) and ctx.isnormal(z) and ctx.isnormal(m)):
|
||||
if ctx.isnan(n) or ctx.isnan(z) or ctx.isnan(m):
|
||||
raise ValueError
|
||||
if complete:
|
||||
|
||||
@@ -395,9 +395,8 @@ def _lambertw_special(ctx, z, k):
|
||||
# Some kind of nan or complex inf/nan?
|
||||
return ctx.ln(z)
|
||||
|
||||
import cmath
|
||||
import math
|
||||
|
||||
import cmath
|
||||
|
||||
def _lambertw_approx_hybrid(z, k):
|
||||
imag_sign = 0
|
||||
@@ -515,7 +514,7 @@ def _lambertw_series(ctx, z, k, tol):
|
||||
def lambertw(ctx, z, k=0):
|
||||
z = ctx.convert(z)
|
||||
k = int(k)
|
||||
if ctx.isspecial(z):
|
||||
if not ctx.isnormal(z):
|
||||
return _lambertw_special(ctx, z, k)
|
||||
prec = ctx.prec
|
||||
ctx.prec += 20 + ctx.mag(k or 1)
|
||||
|
||||
@@ -3,6 +3,7 @@ import decimal
|
||||
import math
|
||||
import operator
|
||||
import random
|
||||
import sys
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
import pytest
|
||||
@@ -11,9 +12,8 @@ from hypothesis import strategies as st
|
||||
|
||||
import mpmath
|
||||
from mpmath import (ceil, fadd, fdiv, floor, fmul, fneg, fp, frac, fsub, inf,
|
||||
isinf, isint, isnan, isnormal, isspecial, iv, monitor, mp,
|
||||
mpc, mpf, mpi, nan, ninf, nint, nint_distance, nstr, pi,
|
||||
workprec)
|
||||
isinf, isint, isnan, isnormal, iv, monitor, mp, mpc, mpf,
|
||||
mpi, nan, ninf, nint, nint_distance, nstr, pi, workprec)
|
||||
from mpmath.libmp import (MPQ, MPZ, finf, fnan, fninf, fnone, fone, from_float,
|
||||
from_int, from_pickable, from_str, isprime, mpf_add,
|
||||
mpf_mul, mpf_sub, round_down, round_nearest,
|
||||
@@ -462,40 +462,50 @@ def test_isnan_etc():
|
||||
assert isinf(MPQ(3, 2)) is False
|
||||
assert isinf(MPQ(0, 1)) is False
|
||||
pytest.raises(TypeError, lambda: isinf(object()))
|
||||
assert isspecial(3) is False
|
||||
assert isspecial(3.5) is False
|
||||
assert isspecial(mpf(3.5)) is False
|
||||
assert isspecial(0) is True
|
||||
assert isspecial(mpf(0)) is True
|
||||
assert isspecial(0.0) is True
|
||||
assert isspecial(inf) is True
|
||||
assert isspecial(-inf) is True
|
||||
assert isspecial(nan) is True
|
||||
assert isspecial(float(inf)) is True
|
||||
assert isspecial(mpc(0, 0)) is True
|
||||
assert isspecial(mpc(3, 0)) is False
|
||||
assert isspecial(mpc(0, 3)) is False
|
||||
assert isspecial(mpc(3, 3)) is False
|
||||
assert isspecial(mpc(0, nan)) is True
|
||||
assert isspecial(mpc(0, inf)) is True
|
||||
assert isspecial(mpc(3, nan)) is True
|
||||
assert isspecial(mpc(3, inf)) is True
|
||||
assert isspecial(mpc(3, -inf)) is True
|
||||
assert isspecial(mpc(nan, 0)) is True
|
||||
assert isspecial(mpc(inf, 0)) is True
|
||||
assert isspecial(mpc(nan, 3)) is True
|
||||
assert isspecial(mpc(inf, 3)) is True
|
||||
assert isspecial(mpc(inf, nan)) is True
|
||||
assert isspecial(mpc(nan, inf)) is True
|
||||
assert isspecial(mpc(nan, nan)) is True
|
||||
assert isspecial(mpc(inf, inf)) is True
|
||||
assert isspecial(MPQ(3, 2)) is False
|
||||
assert isspecial(MPQ(0, 1)) is True
|
||||
pytest.raises(TypeError, lambda: isspecial(object()))
|
||||
assert isspecial(5e-324) is False # issue 946
|
||||
assert fp.isspecial(5e-324) is False
|
||||
assert fp.isspecial(0.0) is True
|
||||
assert fp.isspecial(-0.0) is True
|
||||
assert isnormal(3) is True
|
||||
assert isnormal(3.5) is True
|
||||
assert isnormal(mpf(3.5)) is True
|
||||
assert isnormal(0) is False
|
||||
assert isnormal(mpf(0)) is False
|
||||
assert isnormal(0.0) is False
|
||||
assert isnormal(inf) is False
|
||||
assert isnormal(-inf) is False
|
||||
assert isnormal(nan) is False
|
||||
assert isnormal(float(inf)) is False
|
||||
assert isnormal(mpc(0, 0)) is False
|
||||
assert isnormal(mpc(3, 0)) is True
|
||||
assert isnormal(mpc(0, 3)) is True
|
||||
assert isnormal(mpc(3, 3)) is True
|
||||
assert isnormal(mpc(0, nan)) is False
|
||||
assert isnormal(mpc(0, inf)) is False
|
||||
assert isnormal(mpc(3, nan)) is False
|
||||
assert isnormal(mpc(3, inf)) is False
|
||||
assert isnormal(mpc(3, -inf)) is False
|
||||
assert isnormal(mpc(nan, 0)) is False
|
||||
assert isnormal(mpc(inf, 0)) is False
|
||||
assert isnormal(mpc(nan, 3)) is False
|
||||
assert isnormal(mpc(inf, 3)) is False
|
||||
assert isnormal(mpc(inf, nan)) is False
|
||||
assert isnormal(mpc(nan, inf)) is False
|
||||
assert isnormal(mpc(nan, nan)) is False
|
||||
assert isnormal(mpc(inf, inf)) is False
|
||||
assert isnormal(MPQ(3, 2)) is True
|
||||
assert isnormal(MPQ(0, 1)) is False
|
||||
pytest.raises(TypeError, lambda: isnormal(object()))
|
||||
assert isnormal(math.nextafter(0, 1)) is True # issue 946
|
||||
assert fp.isnormal(math.nextafter(0, 1)) is False
|
||||
assert fp.isnormal(0.0) is False
|
||||
assert fp.isnormal(-0.0) is False
|
||||
assert fp.isnormal(fp.nan) is False
|
||||
assert fp.isnormal(fp.inf) is False
|
||||
assert fp.isnormal(fp.ninf) is False
|
||||
assert fp.isnormal(1.0) is True
|
||||
assert fp.isnormal(sys.float_info.min) is True
|
||||
assert fp.isnormal(1+0j) is True
|
||||
assert fp.isnormal(0j) is False
|
||||
assert fp.isnormal(-0j) is False
|
||||
assert fp.isnormal(1+1j) is True
|
||||
assert fp.isnormal(complex('inf+1j')) is False
|
||||
assert isint(3) is True
|
||||
assert isint(0) is True
|
||||
assert isint(int(3)) is True
|
||||
@@ -545,12 +555,9 @@ def test_isnan_etc():
|
||||
assert mp.isnpint(0 + 0.1j) is False
|
||||
assert mp.isnpint(inf) is False
|
||||
with pytest.deprecated_call():
|
||||
for ctx in [mp, fp]:
|
||||
assert ctx.isnormal(1) is True
|
||||
assert ctx.isnormal(0.0) is False
|
||||
assert ctx.isnormal(ctx.mpc(0)) is False
|
||||
assert ctx.isnormal(ctx.mpc(0, 1)) is True
|
||||
assert ctx.isnormal(ctx.mpc(1, inf)) is False
|
||||
assert fp.is_special(1) is False
|
||||
with pytest.deprecated_call():
|
||||
assert fp.is_special(0.0) is True
|
||||
|
||||
|
||||
def test_isprime():
|
||||
|
||||
Reference in New Issue
Block a user