>From 20b8f23dca46e1383eb5e9f922c1ca93a3fac425 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 17 Apr 2024 10:57:05 +0200 Subject: [PATCH 1/6] getpayload: New module. * lib/math.in.h (getpayload): New declaration. * lib/getpayload.c: New file. * m4/getpayload.m4: New file. * m4/math_h.m4 (gl_MATH_H): Test whether getpayload is declared. (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_GETPAYLOAD. (gl_MATH_H_DEFAULTS): Initialize HAVE_GETPAYLOAD, REPLACE_GETPAYLOAD. * modules/math (Makefile.am): Substitute GNULIB_GETPAYLOAD, HAVE_GETPAYLOAD, REPLACE_GETPAYLOAD. * modules/getpayload: New file. * doc/posix-functions/getpayload.texi: Mention the new module and the glibc bug. --- ChangeLog | 15 +++ doc/posix-functions/getpayload.texi | 12 +- lib/getpayload.c | 54 ++++++++ lib/math.in.h | 24 ++++ m4/getpayload.m4 | 183 ++++++++++++++++++++++++++++ m4/math_h.m4 | 9 +- modules/getpayload | 37 ++++++ modules/math | 3 + 8 files changed, 331 insertions(+), 6 deletions(-) create mode 100644 lib/getpayload.c create mode 100644 m4/getpayload.m4 create mode 100644 modules/getpayload diff --git a/ChangeLog b/ChangeLog index ffe35d5d1d..6fbcff9835 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2024-04-17 Bruno Haible + + getpayload: New module. + * lib/math.in.h (getpayload): New declaration. + * lib/getpayload.c: New file. + * m4/getpayload.m4: New file. + * m4/math_h.m4 (gl_MATH_H): Test whether getpayload is declared. + (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_GETPAYLOAD. + (gl_MATH_H_DEFAULTS): Initialize HAVE_GETPAYLOAD, REPLACE_GETPAYLOAD. + * modules/math (Makefile.am): Substitute GNULIB_GETPAYLOAD, + HAVE_GETPAYLOAD, REPLACE_GETPAYLOAD. + * modules/getpayload: New file. + * doc/posix-functions/getpayload.texi: Mention the new module and the + glibc bug. + 2024-04-16 Sam James wchar: Fix serial number. diff --git a/doc/posix-functions/getpayload.texi b/doc/posix-functions/getpayload.texi index da6154e61f..d5ea38d70c 100644 --- a/doc/posix-functions/getpayload.texi +++ b/doc/posix-functions/getpayload.texi @@ -10,15 +10,19 @@ @url{https://www.gnu.org/software/libc/manual/html_node/FP-Bit-Twiddling.html}. @end ifnotinfo -Gnulib module: --- +Gnulib module: getpayload Portability problems 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. +@item +This function returns a wrong result for non-NaN arguments on some platforms: +@c https://sourceware.org/bugzilla/show_bug.cgi?id=26073 +glibc 2.31. @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. @end itemize diff --git a/lib/getpayload.c b/lib/getpayload.c new file mode 100644 index 0000000000..43979d595f --- /dev/null +++ b/lib/getpayload.c @@ -0,0 +1,54 @@ +/* Extract the payload of a NaN 'double'. + Copyright 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 Bruno Haible. */ + +#include + +/* Specification. */ +#include + +#include +#include +#include + +double +getpayload (const double *value) +{ + if (isnand (*value)) + { +#if DBL_MANT_DIG == 53 + union { uint64_t i; double f; } x; +# if 0 + x.f = *value; +# else + /* On 32-bit x86 processors, as well as on x86_64 processors with + CC="gcc -mfpmath=387", the evaluation of *value above is done + through an 'fldl' instruction, which converts a signalling NaN to + a quiet NaN. See + + for details. Use memcpy to avoid this. */ + memcpy (&x.f, value, sizeof (double)); +# endif + int64_t payload = x.i & (((uint64_t) 1 << (DBL_MANT_DIG - 2)) - 1); + return payload; +#else +# error "Please port gnulib getpayload.c to your platform!" +#endif + } + else + return -1.0; +} diff --git a/lib/math.in.h b/lib/math.in.h index 7bb7976b61..2e7dde2e07 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -2774,6 +2774,30 @@ _GL_WARN_REAL_FLOATING_DECL (signbit); #endif +#if @GNULIB_GETPAYLOAD@ +# if @REPLACE_GETPAYLOAD@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef getpayload +# define getpayload rpl_getpayload +# endif +_GL_FUNCDECL_RPL (getpayload, double, (const double *)); +_GL_CXXALIAS_RPL (getpayload, double, (const double *)); +# else +# if !@HAVE_GETPAYLOAD@ +_GL_FUNCDECL_SYS (getpayload, double, (const double *)); +# endif +_GL_CXXALIAS_SYS (getpayload, double, (const double *)); +# endif +_GL_CXXALIASWARN (getpayload); +#elif defined GNULIB_POSIXCHECK +# undef getpayload +# if HAVE_RAW_DECL_GETPAYLOAD +_GL_WARN_ON_USE (getpayload, "getpayload is unportable - " + "use gnulib module getpayload for portability"); +# endif +#endif + + #if @GNULIB_SETPAYLOADF@ # if !@HAVE_SETPAYLOADF@ _GL_FUNCDECL_SYS (setpayloadf, int, (float *, float)); diff --git a/m4/getpayload.m4 b/m4/getpayload.m4 new file mode 100644 index 0000000000..c41f0c25d8 --- /dev/null +++ b/m4/getpayload.m4 @@ -0,0 +1,183 @@ +# getpayload.m4 +# serial 1 +dnl Copyright 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, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_GETPAYLOADF], +[ + AC_REQUIRE([gl_MATH_H_DEFAULTS]) + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + + gl_MATHFUNC([getpayloadf], [float], [(float const *)]) + if test $gl_cv_func_getpayloadf_no_libm != yes \ + && test $gl_cv_func_getpayloadf_in_libm != yes; then + HAVE_GETPAYLOADF=0 + else + dnl glibc versions < 2.32 return a wrong value, + dnl see . + AC_CACHE_CHECK([whether getpayloadf works], + [gl_cv_func_getpayloadf_works], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#include + ]], + [[float x = 2.718281828459045f; + return getpayloadf (&x) != -1.0f; + ]]) + ], + [gl_cv_func_getpayloadf_works=yes], + [gl_cv_func_getpayloadf_works=no], + [case "$host_os" in + # Guess no on glibc versions < 2.32. + *-gnu* | gnu*) + AC_EGREP_CPP([Unlucky], + [ +#include +#ifdef __GNU_LIBRARY__ + #if (__GLIBC__ == 2 && __GLIBC_MINOR__ < 32) + Unlucky GNU user + #endif +#endif + ], + [gl_cv_func_getpayloadf_works="guessing no"], + [gl_cv_func_getpayloadf_works="guessing yes"]) + ;; + # Guess yes otherwise. + *) gl_cv_func_getpayloadf_works="guessing yes" ;; + esac + ]) + ]) + case "$gl_cv_func_getpayloadf_works" in + *yes) ;; + *) REPLACE_GETPAYLOADF=1 ;; + esac + fi + if test $HAVE_GETPAYLOADF = 0 || test $REPLACE_GETPAYLOADF = 1; then + GETPAYLOADF_LIBM='$(ISNANF_LIBM)' + fi + AC_SUBST([GETPAYLOADF_LIBM]) +]) + +AC_DEFUN_ONCE([gl_FUNC_GETPAYLOAD], +[ + AC_REQUIRE([gl_MATH_H_DEFAULTS]) + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + + gl_MATHFUNC([getpayload], [double], [(double const *)]) + if test $gl_cv_func_getpayload_no_libm != yes \ + && test $gl_cv_func_getpayload_in_libm != yes; then + HAVE_GETPAYLOAD=0 + else + dnl glibc versions < 2.32 return a wrong value, + dnl see . + AC_CACHE_CHECK([whether getpayload works], + [gl_cv_func_getpayload_works], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#include + ]], + [[double x = 2.718281828459045; + return getpayload (&x) != -1.0; + ]]) + ], + [gl_cv_func_getpayload_works=yes], + [gl_cv_func_getpayload_works=no], + [case "$host_os" in + # Guess no on glibc versions < 2.32. + *-gnu* | gnu*) + AC_EGREP_CPP([Unlucky], + [ +#include +#ifdef __GNU_LIBRARY__ + #if (__GLIBC__ == 2 && __GLIBC_MINOR__ < 32) + Unlucky GNU user + #endif +#endif + ], + [gl_cv_func_getpayload_works="guessing no"], + [gl_cv_func_getpayload_works="guessing yes"]) + ;; + # Guess yes otherwise. + *) gl_cv_func_getpayload_works="guessing yes" ;; + esac + ]) + ]) + case "$gl_cv_func_getpayload_works" in + *yes) ;; + *) REPLACE_GETPAYLOAD=1 ;; + esac + fi + if test $HAVE_GETPAYLOAD = 0 || test $REPLACE_GETPAYLOAD = 1; then + GETPAYLOAD_LIBM='$(ISNAND_LIBM)' + fi + AC_SUBST([GETPAYLOAD_LIBM]) +]) + +AC_DEFUN([gl_FUNC_GETPAYLOADL], +[ + AC_REQUIRE([gl_MATH_H_DEFAULTS]) + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_REQUIRE([gl_LONG_DOUBLE_VS_DOUBLE]) + + gl_MATHFUNC([getpayloadl], [long double], [(long double const *)]) + if test $gl_cv_func_getpayloadl_no_libm != yes \ + && test $gl_cv_func_getpayloadl_in_libm != yes; then + HAVE_GETPAYLOADL=0 + else + dnl glibc versions < 2.32 return a wrong value, + dnl see . + AC_CACHE_CHECK([whether getpayloadl works], + [gl_cv_func_getpayloadl_works], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#include + ]], + [[long double x = 2.718281828459045L; + return getpayloadl (&x) != -1.0L; + ]]) + ], + [gl_cv_func_getpayloadl_works=yes], + [gl_cv_func_getpayloadl_works=no], + [case "$host_os" in + # Guess no on glibc versions < 2.32. + *-gnu* | gnu*) + AC_EGREP_CPP([Unlucky], + [ +#include +#ifdef __GNU_LIBRARY__ + #if (__GLIBC__ == 2 && __GLIBC_MINOR__ < 32) + Unlucky GNU user + #endif +#endif + ], + [gl_cv_func_getpayloadl_works="guessing no"], + [gl_cv_func_getpayloadl_works="guessing yes"]) + ;; + # Guess yes otherwise. + *) gl_cv_func_getpayloadl_works="guessing yes" ;; + esac + ]) + ]) + case "$gl_cv_func_getpayloadl_works" in + *yes) ;; + *) REPLACE_GETPAYLOADL=1 ;; + esac + fi + if test $HAVE_GETPAYLOADL = 0 || test $REPLACE_GETPAYLOADL = 1; then + dnl Find libraries needed to link lib/getpayloadl.c. + if test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1; then + AC_REQUIRE([gl_FUNC_GETPAYLOAD]) + GETPAYLOADL_LIBM="$GETPAYLOAD_LIBM" + else + GETPAYLOADL_LIBM='$(ISNANL_LIBM)' + fi + dnl Prerequisite of lib/getpayloadl.c. + gl_LONG_DOUBLE_EXPONENT_LOCATION + fi + AC_SUBST([GETPAYLOADL_LIBM]) +]) diff --git a/m4/math_h.m4 b/m4/math_h.m4 index 7bcacf6959..370ea14051 100644 --- a/m4/math_h.m4 +++ b/m4/math_h.m4 @@ -1,5 +1,5 @@ # math_h.m4 -# serial 132 +# serial 133 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, @@ -43,7 +43,9 @@ AC_DEFUN_ONCE([gl_MATH_H] cbrt cbrtf cbrtl ceilf ceill copysign copysignf copysignl cosf cosl coshf expf expl exp2 exp2f exp2l expm1 expm1f expm1l fabsf fabsl floorf floorl fma fmaf fmal - fmod fmodf fmodl frexpf frexpl hypotf hypotl + fmod fmodf fmodl frexpf frexpl + getpayload + hypotf hypotl ilogb ilogbf ilogbl ldexpf ldexpl log logf logl log10 log10f log10l log1p log1pf log1pl log2 log2f log2l @@ -117,6 +119,7 @@ AC_DEFUN([gl_MATH_H_REQUIRE_DEFAULTS] gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREXPF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREXP]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREXPL]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPAYLOAD]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOT]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOTL]) @@ -223,6 +226,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS] HAVE_FMODF=1; AC_SUBST([HAVE_FMODF]) HAVE_FMODL=1; AC_SUBST([HAVE_FMODL]) HAVE_FREXPF=1; AC_SUBST([HAVE_FREXPF]) + HAVE_GETPAYLOAD=1; AC_SUBST([HAVE_GETPAYLOAD]) HAVE_HYPOTF=1; AC_SUBST([HAVE_HYPOTF]) HAVE_HYPOTL=1; AC_SUBST([HAVE_HYPOTL]) HAVE_ILOGB=1; AC_SUBST([HAVE_ILOGB]) @@ -332,6 +336,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS] REPLACE_FREXPF=0; AC_SUBST([REPLACE_FREXPF]) REPLACE_FREXP=0; AC_SUBST([REPLACE_FREXP]) REPLACE_FREXPL=0; AC_SUBST([REPLACE_FREXPL]) + REPLACE_GETPAYLOAD=0; AC_SUBST([REPLACE_GETPAYLOAD]) REPLACE_HUGE_VAL=0; AC_SUBST([REPLACE_HUGE_VAL]) REPLACE_HYPOT=0; AC_SUBST([REPLACE_HYPOT]) REPLACE_HYPOTF=0; AC_SUBST([REPLACE_HYPOTF]) diff --git a/modules/getpayload b/modules/getpayload new file mode 100644 index 0000000000..5721cb82a9 --- /dev/null +++ b/modules/getpayload @@ -0,0 +1,37 @@ +Description: +getpayload function: extract the payload of a NaN + +Files: +lib/getpayload.c +m4/mathfunc.m4 +m4/getpayload.m4 + +Depends-on: +math +extensions +float [test $HAVE_GETPAYLOAD = 0 || test $REPLACE_GETPAYLOAD = 1] +stdint [test $HAVE_GETPAYLOAD = 0 || test $REPLACE_GETPAYLOAD = 1] +isnand [test $HAVE_GETPAYLOAD = 0 || test $REPLACE_GETPAYLOAD = 1] + +configure.ac: +gl_FUNC_GETPAYLOAD +gl_CONDITIONAL([GL_COND_OBJ_GETPAYLOAD], + [test $HAVE_GETPAYLOAD = 0 || test $REPLACE_GETPAYLOAD = 1]) +gl_MATH_MODULE_INDICATOR([getpayload]) + +Makefile.am: +if GL_COND_OBJ_GETPAYLOAD +lib_SOURCES += getpayload.c +endif + +Include: + + +Link: +$(GETPAYLOAD_LIBM) + +License: +LGPL + +Maintainer: +all diff --git a/modules/math b/modules/math index 70baab7586..b6a15f6d68 100644 --- a/modules/math +++ b/modules/math @@ -75,6 +75,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's/@''GNULIB_FREXPF''@/$(GNULIB_FREXPF)/g' \ -e 's/@''GNULIB_FREXP''@/$(GNULIB_FREXP)/g' \ -e 's/@''GNULIB_FREXPL''@/$(GNULIB_FREXPL)/g' \ + -e 's/@''GNULIB_GETPAYLOAD''@/$(GNULIB_GETPAYLOAD)/g' \ -e 's/@''GNULIB_HYPOT''@/$(GNULIB_HYPOT)/g' \ -e 's/@''GNULIB_HYPOTF''@/$(GNULIB_HYPOTF)/g' \ -e 's/@''GNULIB_HYPOTL''@/$(GNULIB_HYPOTL)/g' \ @@ -176,6 +177,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''HAVE_FMODF''@|$(HAVE_FMODF)|g' \ -e 's|@''HAVE_FMODL''@|$(HAVE_FMODL)|g' \ -e 's|@''HAVE_FREXPF''@|$(HAVE_FREXPF)|g' \ + -e 's|@''HAVE_GETPAYLOAD''@|$(HAVE_GETPAYLOAD)|g' \ -e 's|@''HAVE_HYPOTF''@|$(HAVE_HYPOTF)|g' \ -e 's|@''HAVE_HYPOTL''@|$(HAVE_HYPOTL)|g' \ -e 's|@''HAVE_ILOGB''@|$(HAVE_ILOGB)|g' \ @@ -289,6 +291,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''REPLACE_FREXPF''@|$(REPLACE_FREXPF)|g' \ -e 's|@''REPLACE_FREXP''@|$(REPLACE_FREXP)|g' \ -e 's|@''REPLACE_FREXPL''@|$(REPLACE_FREXPL)|g' \ + -e 's|@''REPLACE_GETPAYLOAD''@|$(REPLACE_GETPAYLOAD)|g' \ -e 's|@''REPLACE_HUGE_VAL''@|$(REPLACE_HUGE_VAL)|g' \ -e 's|@''REPLACE_HYPOT''@|$(REPLACE_HYPOT)|g' \ -e 's|@''REPLACE_HYPOTF''@|$(REPLACE_HYPOTF)|g' \ -- 2.34.1