8000 add `math.signbit` · python/cpython@5e4db08 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5e4db08

Browse files
committed
add math.signbit
1 parent ef4fc86 commit 5e4db08

File tree

6 files changed

+85
-3
lines changed

6 files changed

+85
-3
lines changed

Doc/library/math.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ noted otherwise, all return values are floats.
5959
:func:`isnan(x) <isnan>` Check if *x* is a NaN (not a number)
6060
:func:`ldexp(x, i) <ldexp>` ``x * (2**i)``, inverse of function :func:`frexp`
6161
:func:`nextafter(x, y, steps) <nextafter>` Floating-point value *steps* steps after *x* towards *y*
62+
:func:`signbit(x) <signbit>` Check if *x* is a negative number
6263
:func:`ulp(x) <ulp>` Value of the least significant bit of *x*
6364

6465
**Power, exponential and logarithmic functions**
@@ -431,6 +432,15 @@ Floating point manipulation functions
431432
Added the *steps* argument.
432433

433434

435+
.. function:: signbit(x)
436+
437+
Return :const:`True` if *x* is negative and :const:`False` otherwise.
438+
439+
This is useful to detect the sign bit of zeroes, infinities and NaNs.
440+
441+
.. versionadded:: next
442+
443+
434444
.. function:: ulp(x)
435445

436446
Return the value of the least significant bit of the float *x*:

Doc/whatsnew/3.15.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ math
115115
* Add :func:`math.isnormal` and :func:`math.issubnormal` functions.
116116
(Contributed by Sergey B Kirpichev in :gh:`132908`.)
117117

118+
* Add :func:`math.signbit` function.
119+
(Contributed by Bénédikt Tran in :gh:`135853`.)
120+
118121

119122
os.path
120123
-------

Lib/test/test_math.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,13 @@
1717

1818
eps = 1E-05
1919
NAN = float('nan')
20+
NNAN = float('-nan')
21+
DNAN = decimal.Decimal("nan")
22+
DNNAN = decimal.Decimal("-nan")
2023
INF = float('inf')
2124
NINF = float('-inf')
25+
DINF = decimal.Decimal("inf")
26+
DNINF = decimal.Decimal("-inf")
2227
FLOAT_MAX = sys.float_info.max
2328
FLOAT_MIN = sys.float_info.min
2429

@@ -475,6 +480,14 @@ def testCopysign(self):
475480
# similarly, copysign(2., NAN) could be 2. or -2.
476481
self.assertEqual(abs(math.copysign(2., NAN)), 2.)
477482

483+
def test_signbit(self):
484+
for arg in [0, 0., 1, 1., INF, NAN, DINF, DNAN]:
485+
with self.subTest('positive', arg=arg):
486+
self.assertFalse(math.signbit(arg))
487+
for arg in [-0., -1, -1., NINF, NNAN, DNINF, DNNAN]:
488+
with self.subTest('negative', arg=arg):
489+
self.assertTrue(math.signbit(arg))
490+
478491
def testCos(self):
479492
self.assertRaises(TypeError, math.cos)
480493
self.ftest('cos(-pi/2)', math.cos(-math.pi/2), 0, abs_tol=math.ulp(1))
@@ -1387,7 +1400,6 @@ def __rmul__(self, other):
13871400
args = ((-5, -5, 10), (1.5, 4611686018427387904, 2305843009213693952))
13881401
self.assertEqual(sumprod(*args), 0.0)
13891402

1390-
13911403
@requires_IEEE_754
13921404
@unittest.skipIf(HAVE_DOUBLE_ROUNDING,
13931405
"sumprod() accuracy not guaranteed on machines with double rounding")
@@ -2486,7 +2498,6 @@ def test_nextafter(self):
24862498
with self.assertRaises(ValueError):
24872499
math.nextafter(1.0, INF, steps=-1)
24882500

2489-
24902501
@requires_IEEE_754
24912502
def test_ulp(self):
24922503
self.assertEqual(math.ulp(1.0), sys.float_info.epsilon)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:mod:`math`: expose C99 :func:`~math.signbit` function to determine whether
2+
a floating-point value is negative. Patch by Bénédikt Tran.

Modules/clinic/mathmodule.c.h

Lines changed: 37 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/mathmodule.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,25 @@ FUNC2(remainder, m_remainder,
12331233
"Return x - n*y where n*y is the closest integer multiple of y.\n"
12341234
"In the case where x is exactly halfway between two multiples of\n"
12351235
"y, the nearest even value of n is used. The result is always exact.")
1236+
1237+
/*[clinic input]
1238+
math.signbit
1239+
1240+
x: double
1241+
/
1242+
1243+
Return True if 'x' is negative and False otherwise.
1244+
1245+
This is useful to detect the sign bit of zeroes, infinities and NaNs.
1246+
[clinic start generated code]*/
1247+
1248+
static PyObject *
1249+
math_signbit_impl(PyObject *module, double x)
1250+
/*[clinic end generated code: output=20c5f20156a9b871 input=1765b06afd3c4bd0]*/
1251+
{
1252+
return PyBool_FromLong(signbit(x));
1253+
}
1254+
12361255
FUNC1D(sin, sin, 0,
12371256
"sin($module, x, /)\n--\n\n"
12381257
"Return the sine of x (measured in radians).",
@@ -4199,6 +4218,7 @@ static PyMethodDef math_methods[] = {
41994218
MATH_POW_METHODDEF
42004219
MATH_RADIANS_METHODDEF
42014220
{"remainder", _PyCFunction_CAST(math_remainder), METH_FASTCALL, math_remainder_doc},
4221+
MATH_SIGNBIT_METHODDEF
42024222
{"sin", math_sin, METH_O, math_sin_doc},
42034223
{"sinh", math_sinh, METH_O, math_sinh_doc},
42044224
{"sqrt", math_sqrt, METH_O, math_sqrt_doc},

0 commit comments

Comments
 (0)
0