Skip to content

Commit b2a5ad4

Browse files
picnixzPranjal095
authored andcommitted
pythongh-135853: add math.fmax and math.fmin (python#135888)
1 parent 498066a commit b2a5ad4

File tree

6 files changed

+259
-2
lines changed

6 files changed

+259
-2
lines changed

Doc/library/math.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ noted otherwise, all return values are floats.
4242
:func:`fabs(x) <fabs>` Absolute value of *x*
4343
:func:`floor(x) <floor>` Floor of *x*, the largest integer less than or equal to *x*
4444
:func:`fma(x, y, z) <fma>` Fused multiply-add operation: ``(x * y) + z``
45+
:func:`fmax(x, y) <fmax>` Maximum of two floating-point values
46+
:func:`fmin(x, y) <fmin>` Minimum of two floating-point values
4547
:func:`fmod(x, y) <fmod>` Remainder of division ``x / y``
4648
:func:`modf(x) <modf>` Fractional and integer parts of *x*
4749
:func:`remainder(x, y) <remainder>` Remainder of *x* with respect to *y*
@@ -248,6 +250,30 @@ Floating point arithmetic
248250
.. versionadded:: 3.13
249251

250252

253+
.. function:: fmax(x, y)
254+
255+
Get the larger of two floating-point values, treating NaNs as missing data.
256+
257+
When both operands are (signed) NaNs or zeroes, return ``nan`` and ``0``
258+
respectively and the sign of the result is implementation-defined, that
259+
is, :func:`!fmax` is not required to be sensitive to the sign of such
260+
operands (see Annex F of the C11 standard, §F.10.0.3 and §F.10.9.2).
261+
262+
.. versionadded:: next
263+
264+
265+
.. function:: fmin(x, y)
266+
267+
Get the smaller of two floating-point values, treating NaNs as missing data.
268+
269+
When both operands are (signed) NaNs or zeroes, return ``nan`` and ``0``
270+
respectively and the sign of the result is implementation-defined, that
271+
is, :func:`!fmin` is not required to be sensitive to the sign of such
272+
operands (see Annex F of the C11 standard, §F.10.0.3 and §F.10.9.3).
273+
274+
.. versionadded:: next
275+
276+
251277
.. function:: fmod(x, y)
252278

253279
Return the floating-point remainder of ``x / y``,

Doc/whatsnew/3.15.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ math
212212
* Add :func:`math.isnormal` and :func:`math.issubnormal` functions.
213213
(Contributed by Sergey B Kirpichev in :gh:`132908`.)
214214

215-
* Add :func:`math.signbit` function.
215+
* Add :func:`math.fmax`, :func:`math.fmin` and :func:`math.signbit` functions.
216216
(Contributed by Bénédikt Tran in :gh:`135853`.)
217217

218218

Lib/test/test_math.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
eps = 1E-05
1919
NAN = float('nan')
20+
NNAN = float('-nan')
2021
INF = float('inf')
2122
NINF = float('-inf')
2223
FLOAT_MAX = sys.float_info.max
@@ -636,6 +637,92 @@ def testFmod(self):
636637
self.assertEqual(math.fmod(0.0, NINF), 0.0)
637638
self.assertRaises(ValueError, math.fmod, INF, INF)
638639

640+
def test_fmax(self):
641+
self.assertRaises(TypeError, math.fmax)
642+
self.assertRaises(TypeError, math.fmax, 'x', 'y')
643+
644+
self.assertEqual(math.fmax(0., 0.), 0.)
645+
self.assertEqual(math.fmax(1., 2.), 2.)
646+
self.assertEqual(math.fmax(2., 1.), 2.)
647+
648+
self.assertEqual(math.fmax(+1., +0.), 1.)
649+
self.assertEqual(math.fmax(+0., +1.), 1.)
650+
self.assertEqual(math.fmax(+1., -0.), 1.)
651+
self.assertEqual(math.fmax(-0., +1.), 1.)
652+
653+
self.assertEqual(math.fmax(-1., +0.), 0.)
654+
self.assertEqual(math.fmax(+0., -1.), 0.)
655+
self.assertEqual(math.fmax(-1., -0.), 0.)
656+
self.assertEqual(math.fmax(-0., -1.), 0.)
657+
658+
for x in [NINF, -1., -0., 0., 1., INF]:
659+
self.assertFalse(math.isnan(x))
660+
661+
with self.subTest(x=x, is_negative=math.copysign(1, x) < 0):
662+
self.assertEqual(math.fmax(INF, x), INF)
663+
self.assertEqual(math.fmax(x, INF), INF)
664+
self.assertEqual(math.fmax(NINF, x), x)
665+
self.assertEqual(math.fmax(x, NINF), x)
666+
667+
@requires_IEEE_754
668+
def test_fmax_nans(self):
669+
# When exactly one operand is NaN, the other is returned.
670+
for x in [NINF, -1., -0., 0., 1., INF]:
671+
with self.subTest(x=x, is_negative=math.copysign(1, x) < 0):
672+
self.assertFalse(math.isnan(math.fmax(NAN, x)))
673+
self.assertFalse(math.isnan(math.fmax(x, NAN)))
674+
self.assertFalse(math.isnan(math.fmax(NNAN, x)))
675+
self.assertFalse(math.isnan(math.fmax(x, NNAN)))
676+
# When both operands are NaNs, fmax() returns NaN (see C11, F.10.9.2)
677+
# whose sign is implementation-defined (see C11, F.10.0.3).
678+
self.assertTrue(math.isnan(math.fmax(NAN, NAN)))
679+
self.assertTrue(math.isnan(math.fmax(NNAN, NNAN)))
680+
self.assertTrue(math.isnan(math.fmax(NAN, NNAN)))
681+
self.assertTrue(math.isnan(math.fmax(NNAN, NAN)))
682+
683+
def test_fmin(self):
684+
self.assertRaises(TypeError, math.fmin)
685+
self.assertRaises(TypeError, math.fmin, 'x', 'y')
686+
687+
self.assertEqual(math.fmin(0., 0.), 0.)
688+
self.assertEqual(math.fmin(1., 2.), 1.)
689+
self.assertEqual(math.fmin(2., 1.), 1.)
690+
691+
self.assertEqual(math.fmin(+1., +0.), 0.)
692+
self.assertEqual(math.fmin(+0., +1.), 0.)
693+
self.assertEqual(math.fmin(+1., -0.), 0.)
694+
self.assertEqual(math.fmin(-0., +1.), 0.)
695+
696+
self.assertEqual(math.fmin(-1., +0.), -1.)
697+
self.assertEqual(math.fmin(+0., -1.), -1.)
698+
self.assertEqual(math.fmin(-1., -0.), -1.)
699+
self.assertEqual(math.fmin(-0., -1.), -1.)
700+
701+
for x in [NINF, -1., -0., 0., 1., INF]:
702+
self.assertFalse(math.isnan(x))
703+
704+
with self.subTest(x=x, is_negative=math.copysign(1, x) < 0):
705+
self.assertEqual(math.fmin(INF, x), x)
706+
self.assertEqual(math.fmin(x, INF), x)
707+
self.assertEqual(math.fmin(NINF, x), NINF)
708+
self.assertEqual(math.fmin(x, NINF), NINF)
709+
710+
@requires_IEEE_754
711+
def test_fmin_nans(self):
712+
# When exactly one operand is NaN, the other is returned.
713+
for x in [NINF, -1., -0., 0., 1., INF]:
714+
with self.subTest(x=x, is_negative=math.copysign(1, x) < 0):
715+
self.assertFalse(math.isnan(math.fmin(NAN, x)))
716+
self.assertFalse(math.isnan(math.fmin(x, NAN)))
717+
self.assertFalse(math.isnan(math.fmin(NNAN, x)))
718+
self.assertFalse(math.isnan(math.fmin(x, NNAN)))
719+
# When both operands are NaNs, fmin() returns NaN (see C11, F.10.9.3)
720+
# whose sign is implementation-defined (see C11, F.10.0.3).
721+
self.assertTrue(math.isnan(math.fmin(NAN, NAN)))
722+
self.assertTrue(math.isnan(math.fmin(NNAN, NNAN)))
723+
self.assertTrue(math.isnan(math.fmin(NAN, NNAN)))
724+
self.assertTrue(math.isnan(math.fmin(NNAN, NAN)))
725+
639726
def testFrexp(self):
640727
self.assertRaises(TypeError, math.frexp)
641728

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add :func:`math.fmax` and :func:`math.fmin` to get the larger and smaller of
2+
two floating-point values. Patch by Bénédikt Tran.

Modules/clinic/mathmodule.c.h

Lines changed: 107 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: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,6 +1214,40 @@ math_floor(PyObject *module, PyObject *number)
12141214
return PyLong_FromDouble(floor(x));
12151215
}
12161216

1217+
/*[clinic input]
1218+
math.fmax -> double
1219+
1220+
x: double
1221+
y: double
1222+
/
1223+
1224+
Return the larger of two floating-point arguments.
1225+
[clinic start generated code]*/
1226+
1227+
static double
1228+
math_fmax_impl(PyObject *module, double x, double y)
1229+
/*[clinic end generated code: output=00692358d312fee2 input=021596c027336ffe]*/
1230+
{
1231+
return fmax(x, y);
1232+
}
1233+
1234+
/*[clinic input]
1235+
math.fmin -> double
1236+
1237+
x: double
1238+
y: double
1239+
/
1240+
1241+
Return the smaller of two floating-point arguments.
1242+
[clinic start generated code]*/
1243+
1244+
static double
1245+
math_fmin_impl(PyObject *module, double x, double y)
1246+
/*[clinic end generated code: output=3d5b7826bd292dd9 input=d12e64ccc33f878a]*/
1247+
{
1248+
return fmin(x, y);
1249+
}
1250+
12171251
FUNC1AD(gamma, m_tgamma,
12181252
"gamma($module, x, /)\n--\n\n"
12191253
"Gamma function at x.",
@@ -4192,7 +4226,9 @@ static PyMethodDef math_methods[] = {
41924226
MATH_FACTORIAL_METHODDEF
41934227
MATH_FLOOR_METHODDEF
41944228
MATH_FMA_METHODDEF
4229+
MATH_FMAX_METHODDEF
41954230
MATH_FMOD_METHODDEF
4231+
MATH_FMIN_METHODDEF
41964232
MATH_FREXP_METHODDEF
41974233
MATH_FSUM_METHODDEF
41984234
{"gamma", math_gamma, METH_O, math_gamma_doc},

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy