From a0e8c0276ae0879a6cb07e9fd0fb83530d030c6d Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Fri, 19 Apr 2024 02:22:16 +0200 Subject: [PATCH] totalordermagl: New module. * lib/math.in.h (totalordermagl): New declaration. * lib/totalordermagl.c: New file, based on lib/totalorderl.c. * m4/math_h.m4 (gl_MATH_H): Test whether totalordermagl is declared. (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_TOTALORDERMAGL. (gl_MATH_H_DEFAULTS): Initialize HAVE_TOTALORDERMAGL, REPLACE_TOTALORDERMAGL. * modules/math (Makefile.am): Substitute GNULIB_TOTALORDERMAGL, HAVE_TOTALORDERMAGL, REPLACE_TOTALORDERMAGL. * modules/totalordermagl: New file, based on modules/totalorderl. * doc/posix-functions/totalordermagl.texi: Mention the new module. --- ChangeLog | 14 +++ doc/posix-functions/totalordermagl.texi | 10 +- lib/math.in.h | 30 +++++ lib/totalordermagl.c | 149 ++++++++++++++++++++++++ m4/math_h.m4 | 7 +- modules/math | 3 + modules/totalordermagl | 43 +++++++ 7 files changed, 249 insertions(+), 7 deletions(-) create mode 100644 lib/totalordermagl.c create mode 100644 modules/totalordermagl diff --git a/ChangeLog b/ChangeLog index 3257161de6..7bd8b5072d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2024-04-18 Bruno Haible + + totalordermagl: New module. + * lib/math.in.h (totalordermagl): New declaration. + * lib/totalordermagl.c: New file, based on lib/totalorderl.c. + * m4/math_h.m4 (gl_MATH_H): Test whether totalordermagl is declared. + (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_TOTALORDERMAGL. + (gl_MATH_H_DEFAULTS): Initialize HAVE_TOTALORDERMAGL, + REPLACE_TOTALORDERMAGL. + * modules/math (Makefile.am): Substitute GNULIB_TOTALORDERMAGL, + HAVE_TOTALORDERMAGL, REPLACE_TOTALORDERMAGL. + * modules/totalordermagl: New file, based on modules/totalorderl. + * doc/posix-functions/totalordermagl.texi: Mention the new module. + 2024-04-18 Bruno Haible totalordermagf: Add tests. diff --git a/doc/posix-functions/totalordermagl.texi b/doc/posix-functions/totalordermagl.texi index 45895dd1b8..09d36199f8 100644 --- a/doc/posix-functions/totalordermagl.texi +++ b/doc/posix-functions/totalordermagl.texi @@ -10,14 +10,10 @@ Documentation:@* @url{https://www.gnu.org/software/libc/manual/html_node/FP-Comparison-Functions.html}. @end ifnotinfo -Gnulib module: --- +Gnulib module: totalordermagl Portability problems fixed by Gnulib: @itemize -@end itemize - -Portability problems not fixed by Gnulib: -@itemize @item This function is missing on all non-glibc platforms: glibc 2.24, macOS 11.1, FreeBSD 14.0, NetBSD 10.0, OpenBSD 6.7, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, Solaris 11.4, Cygwin 2.9, mingw, MSVC 14, Android 9.0. @@ -25,3 +21,7 @@ glibc 2.24, macOS 11.1, FreeBSD 14.0, NetBSD 10.0, OpenBSD 6.7, Minix 3.1.8, AIX This function has a different signature on some platforms: glibc 2.30. @end itemize + +Portability problems not fixed by Gnulib: +@itemize +@end itemize diff --git a/lib/math.in.h b/lib/math.in.h index 43a9674fff..96d0da44fd 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -3056,6 +3056,36 @@ _GL_WARN_ON_USE (totalordermag, "totalordermag is unportable - " # endif #endif +#if @GNULIB_TOTALORDERMAGL@ +# if @REPLACE_TOTALORDERMAGL@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef totalordermagl +# define totalordermagl rpl_totalordermagl +# endif +_GL_FUNCDECL_RPL (totalordermagl, int, + (long double const *, long double const *)); +_GL_CXXALIAS_RPL (totalordermagl, int, + (long double const *, long double const *)); +# else +# if !@HAVE_TOTALORDERMAGL@ +_GL_FUNCDECL_SYS (totalordermagl, int, + (long double const *, long double const *)); +# endif +_GL_CXXALIAS_SYS (totalordermagl, int, + (long double const *, long double const *)); +# endif +# if __GLIBC__ >= 2 +_GL_CXXALIASWARN1 (totalordermagl, int, + (long double const *, long double const *)); +# endif +#elif defined GNULIB_POSIXCHECK +# undef totalordermagl +# if HAVE_RAW_DECL_TOTALORDERMAGL +_GL_WARN_ON_USE (totalordermagl, "totalordermagl is unportable - " + "use gnulib module totalordermagl for portability"); +# endif +#endif + _GL_INLINE_HEADER_END diff --git a/lib/totalordermagl.c b/lib/totalordermagl.c new file mode 100644 index 0000000000..85d492f066 --- /dev/null +++ b/lib/totalordermagl.c @@ -0,0 +1,149 @@ +/* Total order of absolute value for 'long double'. + Copyright 2023-2024 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +/* Written by Paul Eggert and Bruno Haible. */ + +#include + +/* Specification. */ +#include + +#if HAVE_SAME_LONG_DOUBLE_AS_DOUBLE + +int +totalordermagl (long double const *x, long double const *y) +{ + return totalordermag ((double const *) x, (double const *) y); +} + +#else + +# include +# include +# include + +# include "verify.h" + +int +totalordermagl (long double const *x, long double const *y) +{ + /* If one of *X, *Y is a NaN and the other isn't, the answer is easy: + the NaN is "greater" than the other argument. */ + int xn = isnanl (*x); + int yn = isnanl (*y); + if (!xn != !yn) + return yn; + /* If none of *X, *Y is a NaN, the '<=' operator on the absolute values + does the job, including for -Infinity and +Infinity. */ + if (!xn) + return (signbit (*x) ? - *x : *x) <= (signbit (*y) ? - *y : *y); + + /* At this point, *X and *Y are NaNs. */ + +# if defined LDBL_SIGNBIT_WORD && defined LDBL_SIGNBIT_BIT + /* The use of a union to extract the bits of the representation of a + 'double' is safe in practice, despite of the "aliasing rules" of + C99, because the GCC docs say + "Even with '-fstrict-aliasing', type-punning is allowed, provided the + memory is accessed through the union type." + and similarly for other compilers. */ +# define NWORDS \ + ((sizeof (long double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) +# if LDBL_MANT_DIG == 64 /* on i386, x86_64, ia64, m68k */ + /* A single uint64_t is enough to hold the payload, since we ignore the sign + bit and the exponent has the maximum possible value. */ + verify (NWORDS >= 3); +# if LDBL_SIGNBIT_WORD == 2 && LDBL_SIGNBIT_BIT == 15 /* on i386, x86_64, ia64 */ + /* Also, LDBL_EXPBIT0_WORD == 2 && LDBL_EXPBIT0_BIT == 0. */ + union { unsigned int word[NWORDS]; uint64_t i; long double value; } xu, yu; + xu.value = *x; + yu.value = *y; + return xu.i <= yu.i; +# elif LDBL_SIGNBIT_WORD == 0 && LDBL_SIGNBIT_BIT == 31 /* on m68k */ + /* Also, LDBL_EXPBIT0_WORD == 0 && LDBL_EXPBIT0_BIT == 16. */ + union { unsigned int word[NWORDS]; long double value; } xu, yu; + xu.value = *x; + yu.value = *y; + /* The payload is in word[1] (high part) and word[2] (low part). */ + return (xu.word[1] < yu.word[1]) + | ((xu.word[1] == yu.word[1]) & (xu.word[2] <= yu.word[2])); +# else +# error "Please port gnulib totalordermagl.c to your platform!" +# endif +# elif LDBL_MANT_DIG == 106 /* on powerpc, powerpc64, powerpc64le */ + /* Two uint64_t are needed to hold the payload. + In the double-double representation, each of the two uint64_t holds + a sign bit. */ + verify (NWORDS == 4); + union { unsigned int word[NWORDS]; uint64_t i[2]; long double value; } + xu = {0}, yu = {0}; + xu.value = *x; + yu.value = *y; + uint64_t xhi = xu.i[0] & ~((uint64_t) 1 << (LDBL_SIGNBIT_BIT + 32)); + uint64_t xlo = xu.i[1] & ~((uint64_t) 1 << (LDBL_SIGNBIT_BIT + 32)); + uint64_t yhi = yu.i[0] & ~((uint64_t) 1 << (LDBL_SIGNBIT_BIT + 32)); + uint64_t ylo = yu.i[1] & ~((uint64_t) 1 << (LDBL_SIGNBIT_BIT + 32)); + return (xhi < yhi) | ((xhi == yhi) & (xlo <= ylo)); +# else + /* Here, LDBL_MANT_DIG == 113 (alpha, arm64, loongarch64, mips64, riscv64, + s390x, sparc64). */ + /* Two uint64_t are needed to hold the payload. */ + verify (NWORDS == 4); + union { unsigned int word[NWORDS]; uint64_t i[2]; long double value; } + xu = {0}, yu = {0}; +# if 0 + xu.value = *x; + yu.value = *y; +# else + /* On Linux/SPARC in 64-bit mode, gcc-6.4.0 -O2 miscompiles the simple + assignments above. Use memcpy as a workaround. */ + memcpy (&xu.value, x, sizeof (long double)); + memcpy (&yu.value, y, sizeof (long double)); +# endif + uint64_t xhi; + uint64_t xlo; + uint64_t yhi; + uint64_t ylo; +# if LDBL_SIGNBIT_WORD < 2 /* big-endian */ + xhi = xu.i[0] & ~((uint64_t) 1 << (LDBL_SIGNBIT_BIT + 32 * (1 - LDBL_SIGNBIT_WORD))); + xlo = xu.i[1]; + yhi = yu.i[0] & ~((uint64_t) 1 << (LDBL_SIGNBIT_BIT + 32 * (1 - LDBL_SIGNBIT_WORD))); + ylo = yu.i[1]; +# else /* little-endian */ + xhi = xu.i[1] & ~((uint64_t) 1 << (LDBL_SIGNBIT_BIT + 32 * (LDBL_SIGNBIT_WORD - 2))); + xlo = xu.i[0]; + yhi = yu.i[1] & ~((uint64_t) 1 << (LDBL_SIGNBIT_BIT + 32 * (LDBL_SIGNBIT_WORD - 2))); + ylo = yu.i[0]; +# endif +# if defined __hppa || (defined __mips__ && !MIPS_NAN2008_LONG_DOUBLE) || defined __sh__ + /* Invert the most significant bit of the mantissa field. Cf. snan.h. */ + xhi ^= + (1ULL << (LDBL_MANT_DIG == 106 + ? 51 /* double-double representation */ + : (LDBL_MANT_DIG - 2) - 64)); /* quad precision representation */ + yhi ^= + (1ULL << (LDBL_MANT_DIG == 106 + ? 51 /* double-double representation */ + : (LDBL_MANT_DIG - 2) - 64)); /* quad precision representation */ +# endif + return (xhi < yhi) | ((xhi == yhi) & (xlo <= ylo)); +# endif +# else +# error "Please port gnulib totalordermagl.c to your platform!" +# endif +} + +#endif diff --git a/m4/math_h.m4 b/m4/math_h.m4 index d07813a016..4b26c9e9dc 100644 --- a/m4/math_h.m4 +++ b/m4/math_h.m4 @@ -1,5 +1,5 @@ # math_h.m4 -# serial 137 +# serial 138 dnl Copyright (C) 2007-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -57,7 +57,7 @@ AC_DEFUN_ONCE([gl_MATH_H], setpayloadsig setpayloadsigf setpayloadsigl sinf sinl sinhf sqrtf sqrtl tanf tanl tanhf totalorder totalorderf totalorderl totalordermag - totalordermagf trunc truncf truncl]) + totalordermagf totalordermagl trunc truncf truncl]) ]) # gl_MATH_MODULE_INDICATOR([modulename]) @@ -186,6 +186,7 @@ AC_DEFUN([gl_MATH_H_REQUIRE_DEFAULTS], gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TOTALORDERL]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TOTALORDERMAG]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TOTALORDERMAGF]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TOTALORDERMAGL]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TRUNC]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TRUNCF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TRUNCL]) @@ -278,6 +279,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], HAVE_TOTALORDERL=1; AC_SUBST([HAVE_TOTALORDERL]) HAVE_TOTALORDERMAG=1; AC_SUBST([HAVE_TOTALORDERMAG]) HAVE_TOTALORDERMAGF=1; AC_SUBST([HAVE_TOTALORDERMAGF]) + HAVE_TOTALORDERMAGL=1; AC_SUBST([HAVE_TOTALORDERMAGL]) HAVE_DECL_ACOSL=1; AC_SUBST([HAVE_DECL_ACOSL]) HAVE_DECL_ASINL=1; AC_SUBST([HAVE_DECL_ASINL]) HAVE_DECL_ATANL=1; AC_SUBST([HAVE_DECL_ATANL]) @@ -399,6 +401,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], REPLACE_TOTALORDERL=0; AC_SUBST([REPLACE_TOTALORDERL]) REPLACE_TOTALORDERMAG=0; AC_SUBST([REPLACE_TOTALORDERMAG]) REPLACE_TOTALORDERMAGF=0; AC_SUBST([REPLACE_TOTALORDERMAGF]) + REPLACE_TOTALORDERMAGL=0; AC_SUBST([REPLACE_TOTALORDERMAGL]) REPLACE_TRUNC=0; AC_SUBST([REPLACE_TRUNC]) REPLACE_TRUNCF=0; AC_SUBST([REPLACE_TRUNCF]) REPLACE_TRUNCL=0; AC_SUBST([REPLACE_TRUNCL]) diff --git a/modules/math b/modules/math index 04fa287209..983c7bf91e 100644 --- a/modules/math +++ b/modules/math @@ -146,6 +146,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's/@''GNULIB_TOTALORDERL''@/$(GNULIB_TOTALORDERL)/g' \ -e 's/@''GNULIB_TOTALORDERMAG''@/$(GNULIB_TOTALORDERMAG)/g' \ -e 's/@''GNULIB_TOTALORDERMAGF''@/$(GNULIB_TOTALORDERMAGF)/g' \ + -e 's/@''GNULIB_TOTALORDERMAGL''@/$(GNULIB_TOTALORDERMAGL)/g' \ -e 's/@''GNULIB_MDA_J0''@/$(GNULIB_MDA_J0)/g' \ -e 's/@''GNULIB_MDA_J1''@/$(GNULIB_MDA_J1)/g' \ -e 's/@''GNULIB_MDA_JN''@/$(GNULIB_MDA_JN)/g' \ @@ -228,6 +229,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''HAVE_TOTALORDERL''@|$(HAVE_TOTALORDERL)|g' \ -e 's|@''HAVE_TOTALORDERMAG''@|$(HAVE_TOTALORDERMAG)|g' \ -e 's|@''HAVE_TOTALORDERMAGF''@|$(HAVE_TOTALORDERMAGF)|g' \ + -e 's|@''HAVE_TOTALORDERMAGL''@|$(HAVE_TOTALORDERMAGL)|g' \ < $@-t2 > $@-t3 $(AM_V_at)sed \ -e 's|@''HAVE_DECL_ACOSL''@|$(HAVE_DECL_ACOSL)|g' \ @@ -356,6 +358,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''REPLACE_TOTALORDERL''@|$(REPLACE_TOTALORDERL)|g' \ -e 's|@''REPLACE_TOTALORDERMAG''@|$(REPLACE_TOTALORDERMAG)|g' \ -e 's|@''REPLACE_TOTALORDERMAGF''@|$(REPLACE_TOTALORDERMAGF)|g' \ + -e 's|@''REPLACE_TOTALORDERMAGL''@|$(REPLACE_TOTALORDERMAGL)|g' \ -e 's|@''REPLACE_TRUNC''@|$(REPLACE_TRUNC)|g' \ -e 's|@''REPLACE_TRUNCF''@|$(REPLACE_TRUNCF)|g' \ -e 's|@''REPLACE_TRUNCL''@|$(REPLACE_TRUNCL)|g' \ diff --git a/modules/totalordermagl b/modules/totalordermagl new file mode 100644 index 0000000000..ca51cd09bc --- /dev/null +++ b/modules/totalordermagl @@ -0,0 +1,43 @@ +Description: +totalordermagl function: total order of absolute value on long double + +Files: +lib/totalordermagl.c +m4/mathfunc.m4 +m4/totalordermag.m4 +m4/nan-mips.m4 +m4/signbit.m4 + +Depends-on: +math +extensions +totalordermag [{ test $HAVE_TOTALORDERMAGL = 0 || test $REPLACE_TOTALORDERMAGL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1] +float [{ test $HAVE_TOTALORDERMAGL = 0 || test $REPLACE_TOTALORDERMAGL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] +stdbool [{ test $HAVE_TOTALORDERMAGL = 0 || test $REPLACE_TOTALORDERMAGL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] +stdint [{ test $HAVE_TOTALORDERMAGL = 0 || test $REPLACE_TOTALORDERMAGL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] +verify [{ test $HAVE_TOTALORDERMAGL = 0 || test $REPLACE_TOTALORDERMAGL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] +isnanl [{ test $HAVE_TOTALORDERMAGL = 0 || test $REPLACE_TOTALORDERMAGL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] +signbit [{ test $HAVE_TOTALORDERMAGL = 0 || test $REPLACE_TOTALORDERMAGL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] + +configure.ac: +gl_FUNC_TOTALORDERMAGL +gl_CONDITIONAL([GL_COND_OBJ_TOTALORDERMAGL], + [test $HAVE_TOTALORDERMAGL = 0 || test $REPLACE_TOTALORDERMAGL = 1]) +gl_MATH_MODULE_INDICATOR([totalordermagl]) + +Makefile.am: +if GL_COND_OBJ_TOTALORDERMAGL +lib_SOURCES += totalordermagl.c +endif + +Include: + + +Link: +$(TOTALORDERMAGL_LIBM) + +License: +LGPL + +Maintainer: +all -- 2.39.5