git: e55db843ef45 - main - lib/msun: Added fmaximum and fminimum family. Tests and man page
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 04 Apr 2026 16:53:00 UTC
The branch main has been updated by fuz:
URL: https://cgit.FreeBSD.org/src/commit/?id=e55db843ef45a8788f69e110d97210fb3968b92f
commit e55db843ef45a8788f69e110d97210fb3968b92f
Author: Jesús Blázquez <jesuscblazquez@gmail.com>
AuthorDate: 2026-03-31 16:31:15 +0000
Commit: Robert Clausecker <fuz@FreeBSD.org>
CommitDate: 2026-04-04 16:52:40 +0000
lib/msun: Added fmaximum and fminimum family. Tests and man page
Starting from the existing fmax{,f,l} functions I've added the fmaximum
family, which handles NaN according to the newest standard (propagating
it).
This commit is a PoC for GSoC 2026.
Reviewed by: fuz, kargl
MFC after: 1 month
Differential Revision: https://reviews.freebsd.org/D55834
---
lib/msun/Makefile | 15 ++-
lib/msun/Symbol.map | 11 ++
lib/msun/man/fmaximum.3 | 103 +++++++++++++++++
lib/msun/src/math.h | 6 +
lib/msun/src/s_fmaximum.c | 65 +++++++++++
lib/msun/src/s_fmaximumf.c | 60 ++++++++++
lib/msun/src/s_fmaximuml.c | 54 +++++++++
lib/msun/src/s_fminimum.c | 66 +++++++++++
lib/msun/src/s_fminimumf.c | 61 +++++++++++
lib/msun/src/s_fminimuml.c | 55 ++++++++++
lib/msun/tests/Makefile | 1 +
lib/msun/tests/fmaximum_fminimum_test.c | 188 ++++++++++++++++++++++++++++++++
12 files changed, 680 insertions(+), 5 deletions(-)
diff --git a/lib/msun/Makefile b/lib/msun/Makefile
index 24989749a502..5112337f6297 100644
--- a/lib/msun/Makefile
+++ b/lib/msun/Makefile
@@ -75,8 +75,9 @@ COMMON_SRCS= b_tgamma.c \
s_exp2.c s_exp2f.c s_expm1.c s_expm1f.c s_fabsf.c s_fdim.c \
s_finite.c s_finitef.c \
s_floor.c s_floorf.c s_fma.c s_fmaf.c \
- s_fmax.c s_fmaxf.c s_fmin.c \
- s_fminf.c s_frexp.c s_frexpf.c s_ilogb.c s_ilogbf.c \
+ s_fmax.c s_fmaxf.c s_fmaximum.c s_fmaximumf.c \
+ s_fmin.c s_fminf.c s_fminimum.c s_fminimumf.c \
+ s_frexp.c s_frexpf.c s_ilogb.c s_ilogbf.c \
s_ilogbl.c s_isfinite.c s_isnan.c s_isnormal.c \
s_llrint.c s_llrintf.c s_llround.c s_llroundf.c s_llroundl.c \
s_log1p.c s_log1pf.c s_logb.c s_logbf.c s_lrint.c s_lrintf.c \
@@ -131,7 +132,8 @@ COMMON_SRCS+= b_tgammal.c catrigl.c \
s_asinhl.c s_atanl.c s_cbrtl.c s_ceill.c s_cexpl.c \
s_clogl.c s_cosl.c s_cospil.c s_cprojl.c \
s_csqrtl.c s_erfl.c s_exp2l.c s_expl.c s_floorl.c s_fmal.c \
- s_fmaxl.c s_fminl.c s_frexpl.c s_logbl.c s_logl.c s_nanl.c \
+ s_fmaxl.c s_fmaximuml.c s_fminl.c s_fminimuml.c \
+ s_frexpl.c s_logbl.c s_logl.c s_nanl.c \
s_nextafterl.c s_nexttoward.c s_remquol.c s_rintl.c s_roundl.c \
s_scalbnl.c s_sinl.c s_sincosl.c s_sinpil.c \
s_tanhl.c s_tanl.c s_tanpil.c s_truncl.c w_cabsl.c
@@ -175,8 +177,8 @@ MAN= acos.3 acosh.3 asin.3 asinh.3 atan.3 atan2.3 atanh.3 \
cpow.3 csqrt.3 erf.3 \
exp.3 fabs.3 fdim.3 \
feclearexcept.3 feenableexcept.3 fegetenv.3 \
- fegetround.3 fenv.3 floor.3 \
- fma.3 fmax.3 fmod.3 hypot.3 ieee.3 ieee_test.3 ilogb.3 j0.3 \
+ fegetround.3 fenv.3 floor.3 fma.3 \
+ fmax.3 fmaximum.3 fmod.3 hypot.3 ieee.3 ieee_test.3 ilogb.3 j0.3 \
lgamma.3 log.3 lrint.3 lround.3 math.3 nan.3 \
nextafter.3 remainder.3 rint.3 \
round.3 scalbn.3 signbit.3 sin.3 sincos.3 \
@@ -229,6 +231,9 @@ MLINKS+=floor.3 floorf.3 floor.3 floorl.3
MLINKS+=fma.3 fmaf.3 fma.3 fmal.3
MLINKS+=fmax.3 fmaxf.3 fmax.3 fmaxl.3 \
fmax.3 fmin.3 fmax.3 fminf.3 fmax.3 fminl.3
+MLINKS+=fmaximum.3 fmaximuml.3 fmaximum.3 fmaximumf.3 \
+ fmaximum.3 fminimum.3 fmaximum.3 fminimumf.3 \
+ fmaximum.3 fminimuml.3
MLINKS+=fmod.3 fmodf.3 fmod.3 fmodl.3
MLINKS+=hypot.3 cabs.3 hypot.3 cabsf.3 hypot.3 cabsl.3 \
hypot.3 hypotf.3 hypot.3 hypotl.3
diff --git a/lib/msun/Symbol.map b/lib/msun/Symbol.map
index 4d5a5e4d7e6e..932cc000fe52 100644
--- a/lib/msun/Symbol.map
+++ b/lib/msun/Symbol.map
@@ -316,3 +316,14 @@ FBSD_1.7 {
tanpif;
tanpil;
};
+
+/* First added in 16.0-CURRENT */
+
+FBSD_1.9 {
+ fmaximum;
+ fmaximumf;
+ fmaximuml;
+ fminimum;
+ fminimumf;
+ fminimuml;
+};
diff --git a/lib/msun/man/fmaximum.3 b/lib/msun/man/fmaximum.3
new file mode 100644
index 000000000000..bd301163a034
--- /dev/null
+++ b/lib/msun/man/fmaximum.3
@@ -0,0 +1,103 @@
+.\" Copyright (c) 2004 David Schultz <das@FreeBSD.org>
+.\" Copyright (c) 2026 Jesús Blázquez <jesuscblazquez@gmail.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd April 4, 2026
+.Dt FMAXIMUM 3
+.Os
+.Sh NAME
+.Nm fmaximum ,
+.Nm fmaximumf ,
+.Nm fmaximuml ,
+.Nm fminimum ,
+.Nm fminimumf ,
+.Nm fminimuml
+.Nd floating-point maximum and minimum functions
+.Sh LIBRARY
+.Lb libm
+.Sh SYNOPSIS
+.In math.h
+.Ft double
+.Fn fmaximum "double x" "double y"
+.Ft float
+.Fn fmaximumf "float x" "float y"
+.Ft "long double"
+.Fn fmaximuml "long double x" "long double y"
+.Ft double
+.Fn fminimum "double x" "double y"
+.Ft float
+.Fn fminimumf "float x" "float y"
+.Ft "long double"
+.Fn fminimuml "long double x" "long double y"
+.Sh DESCRIPTION
+The
+.Fn fmaximum ,
+.Fn fmaximumf ,
+and
+.Fn fmaximuml
+functions return the larger of
+.Fa x
+and
+.Fa y ,
+and likewise, the
+.Fn fminimum ,
+.Fn fminimumf ,
+and
+.Fn fminimuml
+functions return the smaller of
+.Fa x
+and
+.Fa y .
+They treat
+.Li +0.0
+as being larger than
+.Li -0.0 .
+.Pp
+Unlike the
+.Xr fmax 3
+family of functions, which ignore an \*(Na, if either argument to
+.Fn fmaximum
+or
+.Fn fminimum
+is an \*(Na, then the result is an \*(Na.
+These routines do not raise any floating-point exceptions.
+.Sh SEE ALSO
+.Xr fabs 3 ,
+.Xr fdim 3 ,
+.Xr fmax 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn fmaximum ,
+.Fn fmaximumf ,
+.Fn fmaximuml ,
+.Fn fminimum ,
+.Fn fminimumf ,
+and
+.Fn fminimuml
+functions conform to
+.St -isoC-2023 .
+.Sh HISTORY
+These routines first appeared in
+.Fx 16.0 .
diff --git a/lib/msun/src/math.h b/lib/msun/src/math.h
index 25bd64e36a63..103b82c1cdf8 100644
--- a/lib/msun/src/math.h
+++ b/lib/msun/src/math.h
@@ -520,6 +520,12 @@ long double sinpil(long double);
double tanpi(double);
float tanpif(float);
long double tanpil(long double);
+double fmaximum(double, double);
+float fmaximumf(float, float);
+long double fmaximuml(long double, long double);
+double fminimum(double, double);
+float fminimumf(float, float);
+long double fminimuml(long double, long double);
#endif /* __ISO_C_VISIBLE >= 2023 */
__END_DECLS
diff --git a/lib/msun/src/s_fmaximum.c b/lib/msun/src/s_fmaximum.c
new file mode 100644
index 000000000000..f9e1998a84c2
--- /dev/null
+++ b/lib/msun/src/s_fmaximum.c
@@ -0,0 +1,65 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * Copyright (c) 2026 Jesús Blázquez <jesuscblazquez@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <float.h>
+#include <math.h>
+
+#include "fpmath.h"
+
+#ifdef USE_BUILTIN_FMAXIMUM
+double
+fmaximum(double x, double y)
+{
+ return (__builtin_fmaximum(x, y));
+}
+#else
+double
+fmaximum(double x, double y)
+{
+ union IEEEd2bits u[2];
+
+ u[0].d = x;
+ u[1].d = y;
+
+ /* Handle NaN according to ISO/IEC 60559. NaN argument -> NaN return */
+ if ((u[0].bits.exp == 2047 && (u[0].bits.manh | u[0].bits.manl) != 0) ||
+ (u[1].bits.exp == 2047 && (u[1].bits.manh | u[1].bits.manl) != 0))
+ return (NAN);
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[u[0].bits.sign].d);
+
+ return (x > y ? x : y);
+}
+#endif
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(fmaximum, fmaximuml);
+#endif
diff --git a/lib/msun/src/s_fmaximumf.c b/lib/msun/src/s_fmaximumf.c
new file mode 100644
index 000000000000..db4b96c14749
--- /dev/null
+++ b/lib/msun/src/s_fmaximumf.c
@@ -0,0 +1,60 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * Copyright (c) 2026 Jesús Blázquez <jesuscblazquez@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <math.h>
+
+#include "fpmath.h"
+
+#ifdef USE_BUILTIN_FMAXIMUMF
+float
+fmaximumf(float x, float y)
+{
+ return (__builtin_fmaximumf(x, y));
+}
+#else
+float
+fmaximumf(float x, float y)
+{
+ union IEEEf2bits u[2];
+
+ u[0].f = x;
+ u[1].f = y;
+
+ /* Handle NaN according to ISO/IEC 60559. NaN argument -> NaN return */
+ if ((u[0].bits.exp == 255 && u[0].bits.man != 0) ||
+ (u[1].bits.exp == 255 && u[1].bits.man != 0))
+ return (NAN);
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[u[0].bits.sign].f);
+
+ return (x > y ? x : y);
+}
+#endif
diff --git a/lib/msun/src/s_fmaximuml.c b/lib/msun/src/s_fmaximuml.c
new file mode 100644
index 000000000000..c849478cf05a
--- /dev/null
+++ b/lib/msun/src/s_fmaximuml.c
@@ -0,0 +1,54 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * Copyright (c) 2026 Jesús Blázquez <jesuscblazquez@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <math.h>
+
+#include "fpmath.h"
+
+long double
+fmaximuml(long double x, long double y)
+{
+ union IEEEl2bits u[2];
+
+ u[0].e = x;
+ mask_nbit_l(u[0]);
+ u[1].e = y;
+ mask_nbit_l(u[1]);
+
+ /* Handle NaN according to ISO/IEC 60559. NaN argument -> NaN return */
+ if ((u[0].bits.exp == 32767 && (u[0].bits.manh | u[0].bits.manl) != 0) ||
+ (u[1].bits.exp == 32767 && (u[1].bits.manh | u[1].bits.manl) != 0))
+ return (NAN);
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[0].bits.sign ? y : x);
+
+ return (x > y ? x : y);
+}
diff --git a/lib/msun/src/s_fminimum.c b/lib/msun/src/s_fminimum.c
new file mode 100644
index 000000000000..64c81b560626
--- /dev/null
+++ b/lib/msun/src/s_fminimum.c
@@ -0,0 +1,66 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * Copyright (c) 2026 Jesús Blázquez <jesuscblazquez@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <float.h>
+#include <math.h>
+
+#include "fpmath.h"
+
+#ifdef USE_BUILTIN_FMINIMUM
+double
+fminimum(double x, double y)
+{
+ return (__builtin_fminimum(x, y));
+}
+#else
+double
+fminimum(double x, double y)
+{
+ union IEEEd2bits u[2];
+
+ u[0].d = x;
+ u[1].d = y;
+
+ /* Check for NaNs to avoid raising spurious exceptions. */
+ if (u[0].bits.exp == 2047 && (u[0].bits.manh | u[0].bits.manl) != 0 ||
+ u[1].bits.exp == 2047 && (u[1].bits.manh | u[1].bits.manl) != 0)
+ return (NAN);
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[u[1].bits.sign].d);
+
+ return (x < y ? x : y);
+}
+#endif
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(fminimum, fminimuml);
+#endif
+
diff --git a/lib/msun/src/s_fminimumf.c b/lib/msun/src/s_fminimumf.c
new file mode 100644
index 000000000000..d3978f576931
--- /dev/null
+++ b/lib/msun/src/s_fminimumf.c
@@ -0,0 +1,61 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * Copyright (c) 2026 Jesús Blázquez <jesuscblazquez@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <math.h>
+
+#include "fpmath.h"
+
+#ifdef USE_BUILTIN_FMINIMUMF
+float
+fminimumf(float x, float y)
+{
+ return (__builtin_fminimumf(x, y));
+}
+#else
+float
+fminimumf(float x, float y)
+{
+ union IEEEf2bits u[2];
+
+ u[0].f = x;
+ u[1].f = y;
+
+ /* Check for NaNs to avoid raising spurious exceptions. */
+ if (u[0].bits.exp == 255 && u[0].bits.man != 0 ||
+ u[1].bits.exp == 255 && u[1].bits.man != 0)
+ return (NAN);
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[u[1].bits.sign].f);
+
+ return (x < y ? x : y);
+}
+#endif
+
diff --git a/lib/msun/src/s_fminimuml.c b/lib/msun/src/s_fminimuml.c
new file mode 100644
index 000000000000..e2c5527ee319
--- /dev/null
+++ b/lib/msun/src/s_fminimuml.c
@@ -0,0 +1,55 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
+ * Copyright (c) 2026 Jesús Blázquez <jesuscblazquez@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <math.h>
+
+#include "fpmath.h"
+
+long double
+fminimuml(long double x, long double y)
+{
+ union IEEEl2bits u[2];
+
+ u[0].e = x;
+ mask_nbit_l(u[0]);
+ u[1].e = y;
+ mask_nbit_l(u[1]);
+
+ /* Check for NaNs to avoid raising spurious exceptions. */
+ if (u[0].bits.exp == 32767 && (u[0].bits.manh | u[0].bits.manl) != 0 ||
+ u[1].bits.exp == 32767 && (u[1].bits.manh | u[1].bits.manl) != 0)
+ return (NAN);
+
+ /* Handle comparisons of signed zeroes. */
+ if (u[0].bits.sign != u[1].bits.sign)
+ return (u[1].bits.sign ? y : x);
+
+ return (x < y ? x : y);
+}
+
diff --git a/lib/msun/tests/Makefile b/lib/msun/tests/Makefile
index d2a3ebffadb3..d723e0aaf656 100644
--- a/lib/msun/tests/Makefile
+++ b/lib/msun/tests/Makefile
@@ -58,6 +58,7 @@ ATF_TESTS_C+= exponential_test
ATF_TESTS_C+= fenv_test
ATF_TESTS_C+= fma_test
ATF_TESTS_C+= fmaxmin_test
+ATF_TESTS_C+= fmaximum_fminimum_test
ATF_TESTS_C+= ilogb2_test
ATF_TESTS_C+= invtrig_test
ATF_TESTS_C+= invctrig_test
diff --git a/lib/msun/tests/fmaximum_fminimum_test.c b/lib/msun/tests/fmaximum_fminimum_test.c
new file mode 100644
index 000000000000..4641f80dfdad
--- /dev/null
+++ b/lib/msun/tests/fmaximum_fminimum_test.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2008 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Tests for fmaximum{,f,l}() and fminimum{,f,l}()
+ */
+
+#include <sys/cdefs.h>
+#include <fenv.h>
+#include <float.h>
+#include <math.h>
+
+#include "test-utils.h"
+
+#pragma STDC FENV_ACCESS ON
+
+/*
+ * Test whether func(x, y) has the expected result, and make sure no
+ * exceptions are raised.
+ */
+#define TEST(func, type, x, y, expected, rmode) do { \
+ type __x = (x); /* convert before we clear exceptions */ \
+ type __y = (y); \
+ ATF_REQUIRE_EQ(0, feclearexcept(ALL_STD_EXCEPT)); \
+ long double __result = func((__x), (__y)); \
+ CHECK_FP_EXCEPTIONS_MSG(0, ALL_STD_EXCEPT, \
+ #func "(%.20Lg, %.20Lg) rmode%d", (x), (y), rmode); \
+ ATF_CHECK_MSG(fpequal_cs(__result, (expected), true), \
+ #func "(%.20Lg, %.20Lg) rmode%d = %.20Lg, expected %.20Lg", \
+ (x), (y), rmode, __result, (expected)); \
+} while (0)
+
+static void
+testall_r(long double big, long double small, int rmode)
+{
+ long double expected_max, expected_min;
+ if (isnan(big) || isnan(small)) {
+ expected_max = big + small;
+ expected_min = expected_max;
+ } else {
+ expected_max = big;
+ expected_min = small;
+ }
+
+ TEST(fmaximumf, float, big, small, expected_max, rmode);
+ TEST(fmaximumf, float, small, big, expected_max, rmode);
+ TEST(fmaximum, double, big, small, expected_max, rmode);
+ TEST(fmaximum, double, small, big, expected_max, rmode);
+ TEST(fmaximuml, long double, big, small, expected_max, rmode);
+ TEST(fmaximuml, long double, small, big, expected_max, rmode);
+ TEST(fminimumf, float, big, small, expected_min, rmode);
+ TEST(fminimumf, float, small, big, expected_min, rmode);
+ TEST(fminimum, double, big, small, expected_min, rmode);
+ TEST(fminimum, double, small, big, expected_min, rmode);
+ TEST(fminimuml, long double, big, small, expected_min, rmode);
+ TEST(fminimuml, long double, small, big, expected_min, rmode);
+}
+
+/*
+ * Test all the functions: fmaximumf, fmaximum, fmaximuml, fminimumf, fminimum, fminimuml
+ * in all rounding modes and with the arguments in different orders.
+ * The input 'big' must be >= 'small'.
+ */
+static void
+testall(long double big, long double small)
+{
+ static const int rmodes[] = {
+ FE_TONEAREST, FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO
+ };
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ fesetround(rmodes[i]);
+ testall_r(big, small, rmodes[i]);
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(test1);
+ATF_TC_BODY(test1, tc)
+{
+ testall(1.0, 0.0);
+}
+
+ATF_TC_WITHOUT_HEAD(test2);
+ATF_TC_BODY(test2, tc)
+{
+ testall(42.0, nextafterf(42.0, -INFINITY));
+}
+ATF_TC_WITHOUT_HEAD(test3);
+ATF_TC_BODY(test3, tc)
+{
+ testall(nextafterf(42.0, INFINITY), 42.0);
+}
+
+ATF_TC_WITHOUT_HEAD(test4);
+ATF_TC_BODY(test4, tc)
+{
+ testall(-5.0, -5.0);
+}
+
+ATF_TC_WITHOUT_HEAD(test5);
+ATF_TC_BODY(test5, tc)
+{
+ testall(-3.0, -4.0);
+}
+
+ATF_TC_WITHOUT_HEAD(test6);
+ATF_TC_BODY(test6, tc)
+{
+ testall(1.0, NAN);
+}
+ATF_TC_WITHOUT_HEAD(test7);
+ATF_TC_BODY(test7, tc)
+{
+ testall(INFINITY, NAN);
+}
+
+ATF_TC_WITHOUT_HEAD(test8);
+ATF_TC_BODY(test8, tc)
+{
+ testall(INFINITY, 1.0);
+}
+
+ATF_TC_WITHOUT_HEAD(test9);
+ATF_TC_BODY(test9, tc)
+{
+ testall(-3.0, -INFINITY);
+}
+
+ATF_TC_WITHOUT_HEAD(test10);
+ATF_TC_BODY(test10, tc)
+{
+ testall(3.0, -INFINITY);
+}
+
+ATF_TC_WITHOUT_HEAD(test11);
+ATF_TC_BODY(test11, tc)
+{
+ testall(NAN, NAN);
+}
+
+ATF_TC_WITHOUT_HEAD(test12);
+ATF_TC_BODY(test12, tc)
+{
+ testall(0.0, -0.0);
+}
+
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, test1);
+ ATF_TP_ADD_TC(tp, test2);
+ ATF_TP_ADD_TC(tp, test3);
+ ATF_TP_ADD_TC(tp, test4);
+ ATF_TP_ADD_TC(tp, test5);
+ ATF_TP_ADD_TC(tp, test6);
+ ATF_TP_ADD_TC(tp, test7);
+ ATF_TP_ADD_TC(tp, test8);
+ ATF_TP_ADD_TC(tp, test9);
+ ATF_TP_ADD_TC(tp, test10);
+ ATF_TP_ADD_TC(tp, test11);
+ ATF_TP_ADD_TC(tp, test12);
+
+ return (atf_no_error());
+}