https://github.com/python/cpython/commit/5f61cde80a9b33c8e118b1c009fe2aaa4bb87356
commit: 5f61cde80a9b33c8e118b1c009fe2aaa4bb87356
branch: main
author: Sergey B Kirpichev <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2025-06-02T13:38:05+03:00
summary:
gh-132908: Add math.isnormal/issubnormal() functions (GH132935)
files:
A Misc/NEWS.d/next/Library/2025-04-25-16-06-53.gh-issue-132908.wV5rja.rst
M Doc/library/math.rst
M Doc/whatsnew/3.14.rst
M Doc/whatsnew/3.15.rst
M Lib/test/test_math.py
M Modules/clinic/mathmodule.c.h
M Modules/mathmodule.c
diff --git a/Doc/library/math.rst b/Doc/library/math.rst
index 11d3b756e21322..c8061fb16380cd 100644
--- a/Doc/library/math.rst
+++ b/Doc/library/math.rst
@@ -53,6 +53,8 @@ noted otherwise, all return values are floats.
:func:`frexp(x) <frexp>` Mantissa and exponent of
*x*
:func:`isclose(a, b, rel_tol, abs_tol) <isclose>` Check if the values *a*
and *b* are close to each other
:func:`isfinite(x) <isfinite>` Check if *x* is neither
an infinity nor a NaN
+:func:`isnormal(x) <isnormal>` Check if *x* is a normal
number
+:func:`issubnormal(x) <issubnormal>` Check if *x* is a
subnormal number
:func:`isinf(x) <isinf>` Check if *x* is a
positive or negative infinity
:func:`isnan(x) <isnan>` Check if *x* is a NaN
(not a number)
:func:`ldexp(x, i) <ldexp>` ``x * (2**i)``, inverse
of function :func:`frexp`
@@ -373,6 +375,24 @@ Floating point manipulation functions
.. versionadded:: 3.2
+.. function:: isnormal(x)
+
+ Return ``True`` if *x* is a normal number, that is a finite
+ nonzero number that is not a subnormal (see :func:`issubnormal`).
+ Return ``False`` otherwise.
+
+ .. versionadded:: next
+
+
+.. function:: issubnormal(x)
+
+ Return ``True`` if *x* is a subnormal number, that is a finite
+ nonzero number with a magnitude smaller than the smallest positive normal
+ number, see :data:`sys.float_info.min`. Return ``False`` otherwise.
+
+ .. versionadded:: next
+
+
.. function:: isinf(x)
Return ``True`` if *x* is a positive or negative infinity, and
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index 561d1a8914b50c..27dfc75c90fbe9 100644
--- a/Doc/whatsnew/3.14.rst
+++ b/Doc/whatsnew/3.14.rst
@@ -1454,7 +1454,7 @@ math
----
* Added more detailed error messages for domain errors in the module.
- (Contributed by by Charlie Zhao and Sergey B Kirpichev in :gh:`101410`.)
+ (Contributed by Charlie Zhao and Sergey B Kirpichev in :gh:`101410`.)
mimetypes
diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index b342939f70577f..a27a17afdba2a8 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -105,6 +105,13 @@ difflib
(Contributed by Jiahao Li in :gh:`134580`.)
+math
+----
+
+* Add :func:`math.isnormal` and :func:`math.issubnormal` functions.
+ (Contributed by Sergey B Kirpichev in :gh:`132908`.)
+
+
shelve
------
diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py
index d14336f8bac498..384ad5c828d9b3 100644
--- a/Lib/test/test_math.py
+++ b/Lib/test/test_math.py
@@ -1973,6 +1973,28 @@ def testIsfinite(self):
self.assertFalse(math.isfinite(float("inf")))
self.assertFalse(math.isfinite(float("-inf")))
+ def testIsnormal(self):
+ self.assertTrue(math.isnormal(1.25))
+ self.assertTrue(math.isnormal(-1.0))
+ self.assertFalse(math.isnormal(0.0))
+ self.assertFalse(math.isnormal(-0.0))
+ self.assertFalse(math.isnormal(INF))
+ self.assertFalse(math.isnormal(NINF))
+ self.assertFalse(math.isnormal(NAN))
+ self.assertFalse(math.isnormal(FLOAT_MIN/2))
+ self.assertFalse(math.isnormal(-FLOAT_MIN/2))
+
+ def testIssubnormal(self):
+ self.assertFalse(math.issubnormal(1.25))
+ self.assertFalse(math.issubnormal(-1.0))
+ self.assertFalse(math.issubnormal(0.0))
+ self.assertFalse(math.issubnormal(-0.0))
+ self.assertFalse(math.issubnormal(INF))
+ self.assertFalse(math.issubnormal(NINF))
+ self.assertFalse(math.issubnormal(NAN))
+ self.assertTrue(math.issubnormal(FLOAT_MIN/2))
+ self.assertTrue(math.issubnormal(-FLOAT_MIN/2))
+
def testIsnan(self):
self.assertTrue(math.isnan(float("nan")))
self.assertTrue(math.isnan(float("-nan")))
diff --git
a/Misc/NEWS.d/next/Library/2025-04-25-16-06-53.gh-issue-132908.wV5rja.rst
b/Misc/NEWS.d/next/Library/2025-04-25-16-06-53.gh-issue-132908.wV5rja.rst
new file mode 100644
index 00000000000000..e33b061bb9ba1f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-04-25-16-06-53.gh-issue-132908.wV5rja.rst
@@ -0,0 +1,2 @@
+Add :func:`math.isnormal` and :func:`math.issubnormal` functions. Patch by
+Sergey B Kirpichev.
diff --git a/Modules/clinic/mathmodule.c.h b/Modules/clinic/mathmodule.c.h
index 9df73b187bb827..fbb012fb6dd9e1 100644
--- a/Modules/clinic/mathmodule.c.h
+++ b/Modules/clinic/mathmodule.c.h
@@ -628,6 +628,74 @@ math_isfinite(PyObject *module, PyObject *arg)
return return_value;
}
+PyDoc_STRVAR(math_isnormal__doc__,
+"isnormal($module, x, /)\n"
+"--\n"
+"\n"
+"Return True if x is normal, and False otherwise.");
+
+#define MATH_ISNORMAL_METHODDEF \
+ {"isnormal", (PyCFunction)math_isnormal, METH_O, math_isnormal__doc__},
+
+static PyObject *
+math_isnormal_impl(PyObject *module, double x);
+
+static PyObject *
+math_isnormal(PyObject *module, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ double x;
+
+ if (PyFloat_CheckExact(arg)) {
+ x = PyFloat_AS_DOUBLE(arg);
+ }
+ else
+ {
+ x = PyFloat_AsDouble(arg);
+ if (x == -1.0 && PyErr_Occurred()) {
+ goto exit;
+ }
+ }
+ return_value = math_isnormal_impl(module, x);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(math_issubnormal__doc__,
+"issubnormal($module, x, /)\n"
+"--\n"
+"\n"
+"Return True if x is subnormal, and False otherwise.");
+
+#define MATH_ISSUBNORMAL_METHODDEF \
+ {"issubnormal", (PyCFunction)math_issubnormal, METH_O,
math_issubnormal__doc__},
+
+static PyObject *
+math_issubnormal_impl(PyObject *module, double x);
+
+static PyObject *
+math_issubnormal(PyObject *module, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ double x;
+
+ if (PyFloat_CheckExact(arg)) {
+ x = PyFloat_AS_DOUBLE(arg);
+ }
+ else
+ {
+ x = PyFloat_AsDouble(arg);
+ if (x == -1.0 && PyErr_Occurred()) {
+ goto exit;
+ }
+ }
+ return_value = math_issubnormal_impl(module, x);
+
+exit:
+ return return_value;
+}
+
PyDoc_STRVAR(math_isnan__doc__,
"isnan($module, x, /)\n"
"--\n"
@@ -1110,4 +1178,4 @@ math_ulp(PyObject *module, PyObject *arg)
exit:
return return_value;
}
-/*[clinic end generated code: output=77e7b8c161c39843 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=44bba3a0a052a364 input=a9049054013a1b77]*/
diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c
index 71d9c1387f5780..bbbb49115681de 100644
--- a/Modules/mathmodule.c
+++ b/Modules/mathmodule.c
@@ -3118,6 +3118,44 @@ math_isfinite_impl(PyObject *module, double x)
}
+/*[clinic input]
+math.isnormal
+
+ x: double
+ /
+
+Return True if x is normal, and False otherwise.
+[clinic start generated code]*/
+
+static PyObject *
+math_isnormal_impl(PyObject *module, double x)
+/*[clinic end generated code: output=c7b302b5b89c3541 input=fdaa00c58aa7bc17]*/
+{
+ return PyBool_FromLong(isnormal(x));
+}
+
+
+/*[clinic input]
+math.issubnormal
+
+ x: double
+ /
+
+Return True if x is subnormal, and False otherwise.
+[clinic start generated code]*/
+
+static PyObject *
+math_issubnormal_impl(PyObject *module, double x)
+/*[clinic end generated code: output=4e76ac98ddcae761 input=9a20aba7107d0d95]*/
+{
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+ return PyBool_FromLong(issubnormal(x));
+#else
+ return PyBool_FromLong(isfinite(x) && x && !isnormal(x));
+#endif
+}
+
+
/*[clinic input]
math.isnan
@@ -4145,6 +4183,8 @@ static PyMethodDef math_methods[] = {
MATH_HYPOT_METHODDEF
MATH_ISCLOSE_METHODDEF
MATH_ISFINITE_METHODDEF
+ MATH_ISNORMAL_METHODDEF
+ MATH_ISSUBNORMAL_METHODDEF
MATH_ISINF_METHODDEF
MATH_ISNAN_METHODDEF
MATH_ISQRT_METHODDEF
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]