It has been brought to my attention that the use of some clang builtin functions break libm. Consider, #include <math.h> #include <stdio.h> int main(void) { double f, x, y; x = 0.; y = copysign(x, -1.); printf("fmax(% lf % lf) = % lf\n", x, x, fmax(x,x)); printf("fmax(% lf % lf) = % lf\n", x, y, fmax(x,y)); printf("fmax(% lf % lf) = % lf\n", y, x, fmax(y,x)); return (0); } % cc -o z fmax.c -lm && ./z fmax( 0.000000 0.000000) = 0.000000 fmax( 0.000000 -0.000000) = 0.000000 fmax(-0.000000 0.000000) = -0.000000 <--- this is wrong % cc -o z fmax.c -lm -fno-builtin && ./z fmax( 0.000000 0.000000) = 0.000000 fmax( 0.000000 -0.000000) = 0.000000 fmax(-0.000000 0.000000) = 0.000000 % gcc15 -o z fmax.c -lm && ./z fmax( 0.000000 0.000000) = 0.000000 fmax( 0.000000 -0.000000) = 0.000000 fmax(-0.000000 0.000000) = 0.000000 <--- this is correct % -o z fmax.c -lm -fno-builtin && ./z fmax( 0.000000 0.000000) = 0.000000 fmax( 0.000000 -0.000000) = 0.000000 fmax(-0.000000 0.000000) = 0.000000 The FreeBSD documentation has % man fmax ... DESCRIPTION The fmax(), fmaxf(), and fmaxl() functions return the larger of x and y, and likewise, the fmin(), fminf(), and fminl() functions return the smaller of x and y. They treat +0.0 as being larger than -0.0.
This is the same story as memcmp(). The C standard does not specify whether +0 or -0 is returned if the two are passed to fmax() or fmin() and compilers will optimise this. We should instead document that our libm supports a stricter behaviour than what the C standard guarantees (as we did with memcmp()) and recommend that users pass -fno-builtin-fmax and -fno-builtin-fmin or use one of the new C23 functions if they wish to have the stricter behaviour guaranteed.
In particular, I do not believe that this is a fight we can win, and we should pick our battles. We cannot patch every single C compiler to obey our stricter interpretation of the C standard and users might not actually want this, as the stricter behaviour is slower than he more lenient behaviour guaranteed by the standard, and should never be required by portable applications.
(In reply to Robert Clausecker from comment #2) I suppose that a BUGS or CAVEAT section is the best that we can do. I suspect most users don't care about 0 vs -0; and those that do will already have dealt with various compiler behaviors.
Ed, I saw the D56230. Looks ok to me. You may want to add something like: Some compiler enable one to disable optimizations via command-line optimizations such as -fno-builtin-fmax and -fno-builtin-fmin. I'll leave it to you and/or Robert to decide whether a hint is needed.
(In reply to Steve Kargl from comment #4) Ugh, that was some torched English. Some compiler allow one to disable optimizations via command-line options such as -fno-builtin-fmax and -fno-builtin-fmin.
Ugh*ugh. The addition of '#pragma STDC FENV_ACCESS ON' changes clang's to agree with fmax(3). % cc -o z fmax.c -lm && ./z fmax( 0, 0) = 0 expecting 0 fmax(-0, 0) = -0 expecting 0 <-- FAILED fmax( 0, -0) = 0 expecting 0 fmax(-0, -0) = -0 expecting -0 % cc -o z fmax.c -DWITH_PRAGMA -lm && ./z fmax( 0, 0) = 0 expecting 0 fmax(-0, 0) = 0 expecting 0 fmax( 0, -0) = 0 expecting 0 fmax(-0, -0) = -0 expecting -0
A commit in branch main references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=7764e9ca28a9702aed4ba7391e055ec2fcf35c41 commit 7764e9ca28a9702aed4ba7391e055ec2fcf35c41 Author: Ed Maste <emaste@FreeBSD.org> AuthorDate: 2026-04-02 21:59:42 +0000 Commit: Ed Maste <emaste@FreeBSD.org> CommitDate: 2026-04-06 17:00:15 +0000 fmax.3: Add caveat for going beyond C std requirements libm's fmax and fmin family of functions treat +0.0 as greater than -0.0. This is not required by the C standard, so the user may not see this behaviour due to compiler optimization. PR: 294214 Reviewed by: fuz Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D56230 lib/msun/man/fmax.3 | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
A commit in branch stable/15 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=855507463e0d3903d31aa7c084efbf4f819b5d63 commit 855507463e0d3903d31aa7c084efbf4f819b5d63 Author: Ed Maste <emaste@FreeBSD.org> AuthorDate: 2026-04-02 21:59:42 +0000 Commit: Ed Maste <emaste@FreeBSD.org> CommitDate: 2026-04-13 17:35:35 +0000 fmax.3: Add caveat for going beyond C std requirements libm's fmax and fmin family of functions treat +0.0 as greater than -0.0. This is not required by the C standard, so the user may not see this behaviour due to compiler optimization. PR: 294214 Reviewed by: fuz Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D56230 (cherry picked from commit 7764e9ca28a9702aed4ba7391e055ec2fcf35c41) lib/msun/man/fmax.3 | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
A commit in branch stable/14 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=dc61491025091d9e61048cc3cfb18d25ed354a8b commit dc61491025091d9e61048cc3cfb18d25ed354a8b Author: Ed Maste <emaste@FreeBSD.org> AuthorDate: 2026-04-02 21:59:42 +0000 Commit: Ed Maste <emaste@FreeBSD.org> CommitDate: 2026-04-13 17:43:05 +0000 fmax.3: Add caveat for going beyond C std requirements libm's fmax and fmin family of functions treat +0.0 as greater than -0.0. This is not required by the C standard, so the user may not see this behaviour due to compiler optimization. PR: 294214 Reviewed by: fuz Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D56230 (cherry picked from commit 7764e9ca28a9702aed4ba7391e055ec2fcf35c41) (cherry picked from commit 855507463e0d3903d31aa7c084efbf4f819b5d63) lib/msun/man/fmax.3 | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)