ISO C 23 specifies in the (optional, but normative) Annex F also functions for extracting the payload of a quiet or signalling NaN. This patch series implements them.
2024-04-17 Bruno Haible <br...@clisp.org> getpayloadl: Add tests. * tests/test-getpayloadl.c: New file. * modules/getpayloadl-tests: New file. getpayloadl: New module. * lib/math.in.h (getpayloadl): New declaration. * lib/getpayloadl.c: New file. * m4/math_h.m4 (gl_MATH_H): Test whether getpayloadl is declared. (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_GETPAYLOADL. (gl_MATH_H_DEFAULTS): Initialize HAVE_GETPAYLOADL, REPLACE_GETPAYLOADL. * modules/math (Makefile.am): Substitute GNULIB_GETPAYLOADL, HAVE_GETPAYLOADL, REPLACE_GETPAYLOADL. * modules/getpayloadl: New file. * doc/posix-functions/getpayloadl.texi: Mention the new module and the glibc bug. 2024-04-17 Bruno Haible <br...@clisp.org> getpayloadf: Add tests. * tests/test-getpayloadf.c: New file. * modules/getpayloadf-tests: New file. getpayloadf: New module. * lib/math.in.h (getpayloadf): New declaration. * lib/getpayloadf.c: New file. * m4/math_h.m4 (gl_MATH_H): Test whether getpayloadf is declared. (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_GETPAYLOADF. (gl_MATH_H_DEFAULTS): Initialize HAVE_GETPAYLOADF, REPLACE_GETPAYLOADF. * modules/math (Makefile.am): Substitute GNULIB_GETPAYLOADF, HAVE_GETPAYLOADF, REPLACE_GETPAYLOADF. * modules/getpayloadf: New file. * doc/posix-functions/getpayloadf.texi: Mention the new module and the glibc bug. 2024-04-17 Bruno Haible <br...@clisp.org> getpayload: Add tests. * tests/test-getpayload.c: New file. * modules/getpayload-tests: New file. 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.
>From 20b8f23dca46e1383eb5e9f922c1ca93a3fac425 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> 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 <br...@clisp.org> + + 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 <s...@gentoo.org> 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 <https://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible. */ + +#include <config.h> + +/* Specification. */ +#include <math.h> + +#include <float.h> +#include <stdint.h> +#include <string.h> + +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 + <https://lists.gnu.org/archive/html/bug-gnulib/2023-10/msg00060.html> + 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 <https://sourceware.org/bugzilla/show_bug.cgi?id=26073>. + AC_CACHE_CHECK([whether getpayloadf works], + [gl_cv_func_getpayloadf_works], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#include <math.h> + ]], + [[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 <features.h> +#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 <https://sourceware.org/bugzilla/show_bug.cgi?id=26073>. + AC_CACHE_CHECK([whether getpayload works], + [gl_cv_func_getpayload_works], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#include <math.h> + ]], + [[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 <features.h> +#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 <https://sourceware.org/bugzilla/show_bug.cgi?id=26073>. + AC_CACHE_CHECK([whether getpayloadl works], + [gl_cv_func_getpayloadl_works], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#include <math.h> + ]], + [[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 <features.h> +#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: +<math.h> + +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
>From 97313e9122e3f9780f6d259361f5e9e495b6d4eb Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Wed, 17 Apr 2024 10:58:47 +0200 Subject: [PATCH 2/6] getpayload: Add tests. * tests/test-getpayload.c: New file. * modules/getpayload-tests: New file. --- ChangeLog | 4 ++ modules/getpayload-tests | 18 +++++++ tests/test-getpayload.c | 112 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 modules/getpayload-tests create mode 100644 tests/test-getpayload.c diff --git a/ChangeLog b/ChangeLog index 6fbcff9835..495ea4d996 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2024-04-17 Bruno Haible <br...@clisp.org> + getpayload: Add tests. + * tests/test-getpayload.c: New file. + * modules/getpayload-tests: New file. + getpayload: New module. * lib/math.in.h (getpayload): New declaration. * lib/getpayload.c: New file. diff --git a/modules/getpayload-tests b/modules/getpayload-tests new file mode 100644 index 0000000000..d56192d63b --- /dev/null +++ b/modules/getpayload-tests @@ -0,0 +1,18 @@ +Files: +tests/test-getpayload.c +tests/minus-zero.h +tests/infinity.h +tests/signature.h +tests/macros.h + +Depends-on: +setpayload +setpayloadsig +signed-snan + +configure.ac: + +Makefile.am: +TESTS += test-getpayload +check_PROGRAMS += test-getpayload +test_getpayload_LDADD = $(LDADD) @GETPAYLOAD_LIBM@ $(SETPAYLOAD_LIBM) $(SETPAYLOADSIG_LIBM) diff --git a/tests/test-getpayload.c b/tests/test-getpayload.c new file mode 100644 index 0000000000..a6d9d940bd --- /dev/null +++ b/tests/test-getpayload.c @@ -0,0 +1,112 @@ +/* Test getpayload. + Copyright 2024 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +/* Specification. */ +#include <math.h> + +#include "signature.h" +SIGNATURE_CHECK (getpayload, double, (const double *)); + +#include "minus-zero.h" +#include "infinity.h" +#include "signed-snan.h" +#include "macros.h" + +#define PAYLOAD_BITS (53 - 2) /* = (DBL_MANT_DIG - 2) */ + +int +main () +{ + double arg; + double ret; + + /* Test non-NaN arguments. */ + + arg = 2.718281828459045; + ret = getpayload (&arg); + ASSERT (ret == -1.0); + + arg = -3.141592653589793; + ret = getpayload (&arg); + ASSERT (ret == -1.0); + + arg = 0.0; + ret = getpayload (&arg); + ASSERT (ret == -1.0); + + arg = minus_zerod; + ret = getpayload (&arg); + ASSERT (ret == -1.0); + + arg = Infinityd (); + ret = getpayload (&arg); + ASSERT (ret == -1.0); + + arg = - Infinityd (); + ret = getpayload (&arg); + ASSERT (ret == -1.0); + + /* Test quiet NaNs. */ + { + int i; + double p; + + for (i = 0, p = 1.0; i < PAYLOAD_BITS; i++, p *= 2.0) + { + ASSERT (setpayload (&arg, p) == 0); + ret = getpayload (&arg); + ASSERT (ret == p); + /* Test quiet NaNs with sign bit == 1. */ + arg = - arg; + ret = getpayload (&arg); + ASSERT (ret == p); + } + + p = 1320699239819071.0; + ASSERT (setpayload (&arg, p) == 0); + ret = getpayload (&arg); + ASSERT (ret == p); + } + + /* Test signalling NaNs. */ + { + int i; + double p; + + for (i = 0, p = 1.0; i < PAYLOAD_BITS; i++, p *= 2.0) + { + ASSERT (setpayloadsig (&arg, p) == 0); + ret = getpayload (&arg); + ASSERT (ret == p); + } + + p = 1320699239819071.0; + ASSERT (setpayloadsig (&arg, p) == 0); + ret = getpayload (&arg); + ASSERT (ret == p); + + /* Test signalling NaNs with sign bit == 1. */ + memory_double pos_arg = memory_positive_SNaNd (); + memory_double neg_arg = memory_negative_SNaNd (); + double pos_ret = getpayload (&pos_arg.value); + double neg_ret = getpayload (&neg_arg.value); + ASSERT (neg_ret == pos_ret); + } + + return 0; +} -- 2.34.1
>From 282b03a5af7553cd988b91e6380c228a66bfa6c1 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Wed, 17 Apr 2024 11:02:52 +0200 Subject: [PATCH 3/6] getpayloadf: New module. * lib/math.in.h (getpayloadf): New declaration. * lib/getpayloadf.c: New file. * m4/math_h.m4 (gl_MATH_H): Test whether getpayloadf is declared. (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_GETPAYLOADF. (gl_MATH_H_DEFAULTS): Initialize HAVE_GETPAYLOADF, REPLACE_GETPAYLOADF. * modules/math (Makefile.am): Substitute GNULIB_GETPAYLOADF, HAVE_GETPAYLOADF, REPLACE_GETPAYLOADF. * modules/getpayloadf: New file. * doc/posix-functions/getpayloadf.texi: Mention the new module and the glibc bug. --- ChangeLog | 14 ++++++++ doc/posix-functions/getpayloadf.texi | 12 ++++--- lib/getpayloadf.c | 54 ++++++++++++++++++++++++++++ lib/math.in.h | 23 ++++++++++++ m4/math_h.m4 | 7 ++-- modules/getpayloadf | 37 +++++++++++++++++++ modules/math | 3 ++ 7 files changed, 144 insertions(+), 6 deletions(-) create mode 100644 lib/getpayloadf.c create mode 100644 modules/getpayloadf diff --git a/ChangeLog b/ChangeLog index 495ea4d996..6f97325216 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2024-04-17 Bruno Haible <br...@clisp.org> + + getpayloadf: New module. + * lib/math.in.h (getpayloadf): New declaration. + * lib/getpayloadf.c: New file. + * m4/math_h.m4 (gl_MATH_H): Test whether getpayloadf is declared. + (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_GETPAYLOADF. + (gl_MATH_H_DEFAULTS): Initialize HAVE_GETPAYLOADF, REPLACE_GETPAYLOADF. + * modules/math (Makefile.am): Substitute GNULIB_GETPAYLOADF, + HAVE_GETPAYLOADF, REPLACE_GETPAYLOADF. + * modules/getpayloadf: New file. + * doc/posix-functions/getpayloadf.texi: Mention the new module and the + glibc bug. + 2024-04-17 Bruno Haible <br...@clisp.org> getpayload: Add tests. diff --git a/doc/posix-functions/getpayloadf.texi b/doc/posix-functions/getpayloadf.texi index 39bd40ead9..98eecf0109 100644 --- a/doc/posix-functions/getpayloadf.texi +++ b/doc/posix-functions/getpayloadf.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: getpayloadf 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/getpayloadf.c b/lib/getpayloadf.c new file mode 100644 index 0000000000..6e24c55407 --- /dev/null +++ b/lib/getpayloadf.c @@ -0,0 +1,54 @@ +/* Extract the payload of a NaN 'float'. + 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 <https://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible. */ + +#include <config.h> + +/* Specification. */ +#include <math.h> + +#include <float.h> +#include <stdint.h> +#include <string.h> + +float +getpayloadf (const float *value) +{ + if (isnanf (*value)) + { +#if FLT_MANT_DIG == 24 + union { uint32_t i; float 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 'flds' instruction, which converts a signalling NaN to + a quiet NaN. See + <https://lists.gnu.org/archive/html/bug-gnulib/2023-10/msg00060.html> + for details. Use memcpy to avoid this. */ + memcpy (&x.f, value, sizeof (float)); +# endif + int32_t payload = x.i & (((uint32_t) 1 << (FLT_MANT_DIG - 2)) - 1); + return payload; +#else +# error "Please port gnulib getpayloadf.c to your platform!" +#endif + } + else + return -1.0f; +} diff --git a/lib/math.in.h b/lib/math.in.h index 2e7dde2e07..7a59c8cf35 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -2774,6 +2774,29 @@ _GL_WARN_REAL_FLOATING_DECL (signbit); #endif +#if @GNULIB_GETPAYLOADF@ +# if @REPLACE_GETPAYLOADF@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef getpayloadf +# define getpayloadf rpl_getpayloadf +# endif +_GL_FUNCDECL_RPL (getpayloadf, float, (const float *)); +_GL_CXXALIAS_RPL (getpayloadf, float, (const float *)); +# else +# if !@HAVE_GETPAYLOADF@ +_GL_FUNCDECL_SYS (getpayloadf, float, (const float *)); +# endif +_GL_CXXALIAS_SYS (getpayloadf, float, (const float *)); +# endif +_GL_CXXALIASWARN (getpayloadf); +#elif defined GNULIB_POSIXCHECK +# undef getpayloadf +# if HAVE_RAW_DECL_GETPAYLOADF +_GL_WARN_ON_USE (getpayloadf, "getpayloadf is unportable - " + "use gnulib module getpayloadf for portability"); +# endif +#endif + #if @GNULIB_GETPAYLOAD@ # if @REPLACE_GETPAYLOAD@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) diff --git a/m4/math_h.m4 b/m4/math_h.m4 index 370ea14051..12aafb7fe9 100644 --- a/m4/math_h.m4 +++ b/m4/math_h.m4 @@ -1,5 +1,5 @@ # math_h.m4 -# serial 133 +# serial 134 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, @@ -44,7 +44,7 @@ AC_DEFUN_ONCE([gl_MATH_H] expf expl exp2 exp2f exp2l expm1 expm1f expm1l fabsf fabsl floorf floorl fma fmaf fmal fmod fmodf fmodl frexpf frexpl - getpayload + getpayload getpayloadf hypotf hypotl ilogb ilogbf ilogbl ldexpf ldexpl @@ -120,6 +120,7 @@ AC_DEFUN([gl_MATH_H_REQUIRE_DEFAULTS] 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_GETPAYLOADF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOT]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOTL]) @@ -227,6 +228,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS] HAVE_FMODL=1; AC_SUBST([HAVE_FMODL]) HAVE_FREXPF=1; AC_SUBST([HAVE_FREXPF]) HAVE_GETPAYLOAD=1; AC_SUBST([HAVE_GETPAYLOAD]) + HAVE_GETPAYLOADF=1; AC_SUBST([HAVE_GETPAYLOADF]) HAVE_HYPOTF=1; AC_SUBST([HAVE_HYPOTF]) HAVE_HYPOTL=1; AC_SUBST([HAVE_HYPOTL]) HAVE_ILOGB=1; AC_SUBST([HAVE_ILOGB]) @@ -337,6 +339,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS] REPLACE_FREXP=0; AC_SUBST([REPLACE_FREXP]) REPLACE_FREXPL=0; AC_SUBST([REPLACE_FREXPL]) REPLACE_GETPAYLOAD=0; AC_SUBST([REPLACE_GETPAYLOAD]) + REPLACE_GETPAYLOADF=0; AC_SUBST([REPLACE_GETPAYLOADF]) 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/getpayloadf b/modules/getpayloadf new file mode 100644 index 0000000000..a330b4f87a --- /dev/null +++ b/modules/getpayloadf @@ -0,0 +1,37 @@ +Description: +getpayloadf function: extract the payload of a NaN + +Files: +lib/getpayloadf.c +m4/mathfunc.m4 +m4/getpayload.m4 + +Depends-on: +math +extensions +float [test $HAVE_GETPAYLOADF = 0 || test $REPLACE_GETPAYLOADF = 1] +stdint [test $HAVE_GETPAYLOADF = 0 || test $REPLACE_GETPAYLOADF = 1] +isnanf [test $HAVE_GETPAYLOADF = 0 || test $REPLACE_GETPAYLOADF = 1] + +configure.ac: +gl_FUNC_GETPAYLOADF +gl_CONDITIONAL([GL_COND_OBJ_GETPAYLOADF], + [test $HAVE_GETPAYLOADF = 0 || test $REPLACE_GETPAYLOADF = 1]) +gl_MATH_MODULE_INDICATOR([getpayloadf]) + +Makefile.am: +if GL_COND_OBJ_GETPAYLOADF +lib_SOURCES += getpayloadf.c +endif + +Include: +<math.h> + +Link: +$(GETPAYLOADF_LIBM) + +License: +LGPL + +Maintainer: +all diff --git a/modules/math b/modules/math index b6a15f6d68..a8c9646124 100644 --- a/modules/math +++ b/modules/math @@ -76,6 +76,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's/@''GNULIB_FREXP''@/$(GNULIB_FREXP)/g' \ -e 's/@''GNULIB_FREXPL''@/$(GNULIB_FREXPL)/g' \ -e 's/@''GNULIB_GETPAYLOAD''@/$(GNULIB_GETPAYLOAD)/g' \ + -e 's/@''GNULIB_GETPAYLOADF''@/$(GNULIB_GETPAYLOADF)/g' \ -e 's/@''GNULIB_HYPOT''@/$(GNULIB_HYPOT)/g' \ -e 's/@''GNULIB_HYPOTF''@/$(GNULIB_HYPOTF)/g' \ -e 's/@''GNULIB_HYPOTL''@/$(GNULIB_HYPOTL)/g' \ @@ -178,6 +179,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''HAVE_FMODL''@|$(HAVE_FMODL)|g' \ -e 's|@''HAVE_FREXPF''@|$(HAVE_FREXPF)|g' \ -e 's|@''HAVE_GETPAYLOAD''@|$(HAVE_GETPAYLOAD)|g' \ + -e 's|@''HAVE_GETPAYLOADF''@|$(HAVE_GETPAYLOADF)|g' \ -e 's|@''HAVE_HYPOTF''@|$(HAVE_HYPOTF)|g' \ -e 's|@''HAVE_HYPOTL''@|$(HAVE_HYPOTL)|g' \ -e 's|@''HAVE_ILOGB''@|$(HAVE_ILOGB)|g' \ @@ -292,6 +294,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''REPLACE_FREXP''@|$(REPLACE_FREXP)|g' \ -e 's|@''REPLACE_FREXPL''@|$(REPLACE_FREXPL)|g' \ -e 's|@''REPLACE_GETPAYLOAD''@|$(REPLACE_GETPAYLOAD)|g' \ + -e 's|@''REPLACE_GETPAYLOADF''@|$(REPLACE_GETPAYLOADF)|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
>From e32e13caaef5f0cf9d6fc47a042251832746b7b7 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Wed, 17 Apr 2024 11:03:53 +0200 Subject: [PATCH 4/6] getpayloadf: Add tests. * tests/test-getpayloadf.c: New file. * modules/getpayloadf-tests: New file. --- ChangeLog | 4 ++ modules/getpayloadf-tests | 18 ++++++ tests/test-getpayloadf.c | 112 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 modules/getpayloadf-tests create mode 100644 tests/test-getpayloadf.c diff --git a/ChangeLog b/ChangeLog index 6f97325216..863442a263 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2024-04-17 Bruno Haible <br...@clisp.org> + getpayloadf: Add tests. + * tests/test-getpayloadf.c: New file. + * modules/getpayloadf-tests: New file. + getpayloadf: New module. * lib/math.in.h (getpayloadf): New declaration. * lib/getpayloadf.c: New file. diff --git a/modules/getpayloadf-tests b/modules/getpayloadf-tests new file mode 100644 index 0000000000..1901fc43f9 --- /dev/null +++ b/modules/getpayloadf-tests @@ -0,0 +1,18 @@ +Files: +tests/test-getpayloadf.c +tests/minus-zero.h +tests/infinity.h +tests/signature.h +tests/macros.h + +Depends-on: +setpayloadf +setpayloadsigf +signed-snan + +configure.ac: + +Makefile.am: +TESTS += test-getpayloadf +check_PROGRAMS += test-getpayloadf +test_getpayloadf_LDADD = $(LDADD) @GETPAYLOADF_LIBM@ $(SETPAYLOADF_LIBM) $(SETPAYLOADSIGF_LIBM) diff --git a/tests/test-getpayloadf.c b/tests/test-getpayloadf.c new file mode 100644 index 0000000000..f0ec047235 --- /dev/null +++ b/tests/test-getpayloadf.c @@ -0,0 +1,112 @@ +/* Test getpayloadf. + Copyright 2024 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +/* Specification. */ +#include <math.h> + +#include "signature.h" +SIGNATURE_CHECK (getpayloadf, float, (const float *)); + +#include "minus-zero.h" +#include "infinity.h" +#include "signed-snan.h" +#include "macros.h" + +#define PAYLOAD_BITS (24 - 2) /* = (FLT_MANT_DIG - 2) */ + +int +main () +{ + float arg; + float ret; + + /* Test non-NaN arguments. */ + + arg = 2.718281828459045f; + ret = getpayloadf (&arg); + ASSERT (ret == -1.0f); + + arg = -3.141592653589793f; + ret = getpayloadf (&arg); + ASSERT (ret == -1.0f); + + arg = 0.0f; + ret = getpayloadf (&arg); + ASSERT (ret == -1.0f); + + arg = minus_zerof; + ret = getpayloadf (&arg); + ASSERT (ret == -1.0f); + + arg = Infinityf (); + ret = getpayloadf (&arg); + ASSERT (ret == -1.0f); + + arg = - Infinityf (); + ret = getpayloadf (&arg); + ASSERT (ret == -1.0f); + + /* Test quiet NaNs. */ + { + int i; + float p; + + for (i = 0, p = 1.0f; i < PAYLOAD_BITS; i++, p *= 2.0f) + { + ASSERT (setpayloadf (&arg, p) == 0); + ret = getpayloadf (&arg); + ASSERT (ret == p); + /* Test quiet NaNs with sign bit == 1. */ + arg = - arg; + ret = getpayloadf (&arg); + ASSERT (ret == p); + } + + p = 2300902.0f; + ASSERT (setpayloadf (&arg, p) == 0); + ret = getpayloadf (&arg); + ASSERT (ret == p); + } + + /* Test signalling NaNs. */ + { + int i; + float p; + + for (i = 0, p = 1.0f; i < PAYLOAD_BITS; i++, p *= 2.0f) + { + ASSERT (setpayloadsigf (&arg, p) == 0); + ret = getpayloadf (&arg); + ASSERT (ret == p); + } + + p = 2300902.0f; + ASSERT (setpayloadsigf (&arg, p) == 0); + ret = getpayloadf (&arg); + ASSERT (ret == p); + + /* Test signalling NaNs with sign bit == 1. */ + memory_float pos_arg = memory_positive_SNaNf (); + memory_float neg_arg = memory_negative_SNaNf (); + float pos_ret = getpayloadf (&pos_arg.value); + float neg_ret = getpayloadf (&neg_arg.value); + ASSERT (neg_ret == pos_ret); + } + + return 0; +} -- 2.34.1
>From 63f3bcdc9a42de17310dc636e031385a0feeaeff Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Wed, 17 Apr 2024 11:08:40 +0200 Subject: [PATCH 5/6] getpayloadl: New module. * lib/math.in.h (getpayloadl): New declaration. * lib/getpayloadl.c: New file. * m4/math_h.m4 (gl_MATH_H): Test whether getpayloadl is declared. (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_GETPAYLOADL. (gl_MATH_H_DEFAULTS): Initialize HAVE_GETPAYLOADL, REPLACE_GETPAYLOADL. * modules/math (Makefile.am): Substitute GNULIB_GETPAYLOADL, HAVE_GETPAYLOADL, REPLACE_GETPAYLOADL. * modules/getpayloadl: New file. * doc/posix-functions/getpayloadl.texi: Mention the new module and the glibc bug. --- ChangeLog | 14 ++++ doc/posix-functions/getpayloadl.texi | 12 ++-- lib/getpayloadl.c | 100 +++++++++++++++++++++++++++ lib/math.in.h | 23 ++++++ m4/math_h.m4 | 7 +- modules/getpayloadl | 40 +++++++++++ modules/math | 3 + 7 files changed, 193 insertions(+), 6 deletions(-) create mode 100644 lib/getpayloadl.c create mode 100644 modules/getpayloadl diff --git a/ChangeLog b/ChangeLog index 863442a263..bcc40cb255 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2024-04-17 Bruno Haible <br...@clisp.org> + + getpayloadl: New module. + * lib/math.in.h (getpayloadl): New declaration. + * lib/getpayloadl.c: New file. + * m4/math_h.m4 (gl_MATH_H): Test whether getpayloadl is declared. + (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_GETPAYLOADL. + (gl_MATH_H_DEFAULTS): Initialize HAVE_GETPAYLOADL, REPLACE_GETPAYLOADL. + * modules/math (Makefile.am): Substitute GNULIB_GETPAYLOADL, + HAVE_GETPAYLOADL, REPLACE_GETPAYLOADL. + * modules/getpayloadl: New file. + * doc/posix-functions/getpayloadl.texi: Mention the new module and the + glibc bug. + 2024-04-17 Bruno Haible <br...@clisp.org> getpayloadf: Add tests. diff --git a/doc/posix-functions/getpayloadl.texi b/doc/posix-functions/getpayloadl.texi index b3f6471a67..8b1273b367 100644 --- a/doc/posix-functions/getpayloadl.texi +++ b/doc/posix-functions/getpayloadl.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: getpayloadl 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/getpayloadl.c b/lib/getpayloadl.c new file mode 100644 index 0000000000..6eefb56182 --- /dev/null +++ b/lib/getpayloadl.c @@ -0,0 +1,100 @@ +/* Extract the payload of a NaN 'long 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 <https://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible. */ + +#include <config.h> + +/* Specification. */ +#include <math.h> + +#if HAVE_SAME_LONG_DOUBLE_AS_DOUBLE + +long double +getpayloadl (const long double *value) +{ + return getpayload ((const double *) value); +} + +#else + +# include <float.h> +# include <stdint.h> + +# include "snan.h" + +/* 2^(LDBL_MANT_DIG-1). */ +# define TWO_LDBL_MANT_DIG \ + ((long double) (1U << ((LDBL_MANT_DIG - 1) / 4)) \ + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 1) / 4)) \ + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 2) / 4)) \ + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 3) / 4))) + +long double +getpayloadl (const long double *value) +{ + if (isnanl (*value)) + { +# if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 106 || LDBL_MANT_DIG == 113) \ + && defined LDBL_EXPBIT0_WORD && defined LDBL_EXPBIT0_BIT + memory_long_double x; + x.value = *value; +# if LDBL_MANT_DIG == 64 /* on i386, x86_64, ia64, m68k */ + int64_t payload; +# if LDBL_EXPBIT0_WORD == 2 && LDBL_EXPBIT0_BIT == 0 /* on i386, x86_64, ia64 */ + payload = ((uint64_t) (x.word[1] & 0x3FFFFFFFU) << 32) | x.word[0]; +# elif LDBL_EXPBIT0_WORD == 0 && LDBL_EXPBIT0_BIT == 16 /* on m68k */ + payload = ((uint64_t) (x.word[1] & 0x3FFFFFFFU) << 32) | x.word[2]; +# else +# error "Please port gnulib getpayloadl.c to your platform!" +# endif + return payload; +# endif +# if LDBL_MANT_DIG == 106 /* on powerpc, powerpc64, powerpc64le */ + int64_t payload; +# if LDBL_EXPBIT0_BIT == 20 + payload = ((uint64_t) (x.word[LDBL_EXPBIT0_WORD] & 0x0007FFFFU) << 32) + | x.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 1 : -1)]; +# else +# error "Please port gnulib getpayloadl.c to your platform!" +# endif + return payload; +# endif +# if LDBL_MANT_DIG == 113 /* on alpha, arm64, loongarch64, mips64, riscv64, s390x, sparc64 */ +# if LDBL_EXPBIT0_BIT == 16 + memory_long_double pl; + pl.value = TWO_LDBL_MANT_DIG; + pl.word[LDBL_EXPBIT0_WORD] |= x.word[LDBL_EXPBIT0_WORD] & 0x00007FFFU; + pl.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 1 : -1)] = + x.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 1 : -1)]; + pl.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 2 : -2)] = + x.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 2 : -2)]; + pl.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 3 : -3)] = + x.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 3 : -3)]; + return pl.value - TWO_LDBL_MANT_DIG; +# else +# error "Please port gnulib getpayloadl.c to your platform!" +# endif +# endif +# else +# error "Please port gnulib getpayloadl.c to your platform!" +# endif + } + else + return -1.0L; +} + +#endif diff --git a/lib/math.in.h b/lib/math.in.h index 7a59c8cf35..84b743e7ab 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -2820,6 +2820,29 @@ _GL_WARN_ON_USE (getpayload, "getpayload is unportable - " # endif #endif +#if @GNULIB_GETPAYLOADL@ +# if @REPLACE_GETPAYLOADL@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef getpayloadl +# define getpayloadl rpl_getpayloadl +# endif +_GL_FUNCDECL_RPL (getpayloadl, long double, (const long double *)); +_GL_CXXALIAS_RPL (getpayloadl, long double, (const long double *)); +# else +# if !@HAVE_GETPAYLOADL@ +_GL_FUNCDECL_SYS (getpayloadl, long double, (const long double *)); +# endif +_GL_CXXALIAS_SYS (getpayloadl, long double, (const long double *)); +# endif +_GL_CXXALIASWARN (getpayloadl); +#elif defined GNULIB_POSIXCHECK +# undef getpayloadl +# if HAVE_RAW_DECL_GETPAYLOADL +_GL_WARN_ON_USE (getpayloadl, "getpayloadl is unportable - " + "use gnulib module getpayloadl for portability"); +# endif +#endif + #if @GNULIB_SETPAYLOADF@ # if !@HAVE_SETPAYLOADF@ diff --git a/m4/math_h.m4 b/m4/math_h.m4 index 12aafb7fe9..217c4d225d 100644 --- a/m4/math_h.m4 +++ b/m4/math_h.m4 @@ -1,5 +1,5 @@ # math_h.m4 -# serial 134 +# serial 135 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, @@ -44,7 +44,7 @@ AC_DEFUN_ONCE([gl_MATH_H] expf expl exp2 exp2f exp2l expm1 expm1f expm1l fabsf fabsl floorf floorl fma fmaf fmal fmod fmodf fmodl frexpf frexpl - getpayload getpayloadf + getpayload getpayloadf getpayloadl hypotf hypotl ilogb ilogbf ilogbl ldexpf ldexpl @@ -121,6 +121,7 @@ AC_DEFUN([gl_MATH_H_REQUIRE_DEFAULTS] gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREXPL]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPAYLOAD]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPAYLOADF]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPAYLOADL]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOT]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOTL]) @@ -229,6 +230,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS] HAVE_FREXPF=1; AC_SUBST([HAVE_FREXPF]) HAVE_GETPAYLOAD=1; AC_SUBST([HAVE_GETPAYLOAD]) HAVE_GETPAYLOADF=1; AC_SUBST([HAVE_GETPAYLOADF]) + HAVE_GETPAYLOADL=1; AC_SUBST([HAVE_GETPAYLOADL]) HAVE_HYPOTF=1; AC_SUBST([HAVE_HYPOTF]) HAVE_HYPOTL=1; AC_SUBST([HAVE_HYPOTL]) HAVE_ILOGB=1; AC_SUBST([HAVE_ILOGB]) @@ -340,6 +342,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS] REPLACE_FREXPL=0; AC_SUBST([REPLACE_FREXPL]) REPLACE_GETPAYLOAD=0; AC_SUBST([REPLACE_GETPAYLOAD]) REPLACE_GETPAYLOADF=0; AC_SUBST([REPLACE_GETPAYLOADF]) + REPLACE_GETPAYLOADL=0; AC_SUBST([REPLACE_GETPAYLOADL]) 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/getpayloadl b/modules/getpayloadl new file mode 100644 index 0000000000..3ddd0a57ef --- /dev/null +++ b/modules/getpayloadl @@ -0,0 +1,40 @@ +Description: +getpayloadl function: extract the payload of a NaN + +Files: +lib/getpayloadl.c +m4/mathfunc.m4 +m4/getpayload.m4 +m4/exponentl.m4 + +Depends-on: +math +extensions +getpayload [{ test $HAVE_GETPAYLOADL = 0 || test $REPLACE_GETPAYLOADL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1] +float [{ test $HAVE_GETPAYLOADL = 0 || test $REPLACE_GETPAYLOADL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] +stdint [{ test $HAVE_GETPAYLOADL = 0 || test $REPLACE_GETPAYLOADL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] +isnanl [{ test $HAVE_GETPAYLOADL = 0 || test $REPLACE_GETPAYLOADL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] +snan [{ test $HAVE_GETPAYLOADL = 0 || test $REPLACE_GETPAYLOADL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] + +configure.ac: +gl_FUNC_GETPAYLOADL +gl_CONDITIONAL([GL_COND_OBJ_GETPAYLOADL], + [test $HAVE_GETPAYLOADL = 0 || test $REPLACE_GETPAYLOADL = 1]) +gl_MATH_MODULE_INDICATOR([getpayloadl]) + +Makefile.am: +if GL_COND_OBJ_GETPAYLOADL +lib_SOURCES += getpayloadl.c +endif + +Include: +<math.h> + +Link: +$(GETPAYLOADL_LIBM) + +License: +LGPL + +Maintainer: +all diff --git a/modules/math b/modules/math index a8c9646124..8c853f0979 100644 --- a/modules/math +++ b/modules/math @@ -77,6 +77,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's/@''GNULIB_FREXPL''@/$(GNULIB_FREXPL)/g' \ -e 's/@''GNULIB_GETPAYLOAD''@/$(GNULIB_GETPAYLOAD)/g' \ -e 's/@''GNULIB_GETPAYLOADF''@/$(GNULIB_GETPAYLOADF)/g' \ + -e 's/@''GNULIB_GETPAYLOADL''@/$(GNULIB_GETPAYLOADL)/g' \ -e 's/@''GNULIB_HYPOT''@/$(GNULIB_HYPOT)/g' \ -e 's/@''GNULIB_HYPOTF''@/$(GNULIB_HYPOTF)/g' \ -e 's/@''GNULIB_HYPOTL''@/$(GNULIB_HYPOTL)/g' \ @@ -180,6 +181,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''HAVE_FREXPF''@|$(HAVE_FREXPF)|g' \ -e 's|@''HAVE_GETPAYLOAD''@|$(HAVE_GETPAYLOAD)|g' \ -e 's|@''HAVE_GETPAYLOADF''@|$(HAVE_GETPAYLOADF)|g' \ + -e 's|@''HAVE_GETPAYLOADL''@|$(HAVE_GETPAYLOADL)|g' \ -e 's|@''HAVE_HYPOTF''@|$(HAVE_HYPOTF)|g' \ -e 's|@''HAVE_HYPOTL''@|$(HAVE_HYPOTL)|g' \ -e 's|@''HAVE_ILOGB''@|$(HAVE_ILOGB)|g' \ @@ -295,6 +297,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''REPLACE_FREXPL''@|$(REPLACE_FREXPL)|g' \ -e 's|@''REPLACE_GETPAYLOAD''@|$(REPLACE_GETPAYLOAD)|g' \ -e 's|@''REPLACE_GETPAYLOADF''@|$(REPLACE_GETPAYLOADF)|g' \ + -e 's|@''REPLACE_GETPAYLOADL''@|$(REPLACE_GETPAYLOADL)|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
>From 507b790ed13750b4c81afff56f403d2aeac4ca72 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Wed, 17 Apr 2024 11:09:13 +0200 Subject: [PATCH 6/6] getpayloadl: Add tests. * tests/test-getpayloadl.c: New file. * modules/getpayloadl-tests: New file. --- ChangeLog | 4 ++ modules/getpayloadl-tests | 18 ++++++ tests/test-getpayloadl.c | 119 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 modules/getpayloadl-tests create mode 100644 tests/test-getpayloadl.c diff --git a/ChangeLog b/ChangeLog index bcc40cb255..e6b4eff89b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2024-04-17 Bruno Haible <br...@clisp.org> + getpayloadl: Add tests. + * tests/test-getpayloadl.c: New file. + * modules/getpayloadl-tests: New file. + getpayloadl: New module. * lib/math.in.h (getpayloadl): New declaration. * lib/getpayloadl.c: New file. diff --git a/modules/getpayloadl-tests b/modules/getpayloadl-tests new file mode 100644 index 0000000000..02433a206d --- /dev/null +++ b/modules/getpayloadl-tests @@ -0,0 +1,18 @@ +Files: +tests/test-getpayloadl.c +tests/minus-zero.h +tests/infinity.h +tests/signature.h +tests/macros.h + +Depends-on: +setpayloadl +setpayloadsigl +signed-snan + +configure.ac: + +Makefile.am: +TESTS += test-getpayloadl +check_PROGRAMS += test-getpayloadl +test_getpayloadl_LDADD = $(LDADD) @GETPAYLOADL_LIBM@ $(SETPAYLOADL_LIBM) $(SETPAYLOADSIGL_LIBM) diff --git a/tests/test-getpayloadl.c b/tests/test-getpayloadl.c new file mode 100644 index 0000000000..4aaa7c5c0c --- /dev/null +++ b/tests/test-getpayloadl.c @@ -0,0 +1,119 @@ +/* Test getpayloadl. + Copyright 2024 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +/* Specification. */ +#include <math.h> + +#include "signature.h" +SIGNATURE_CHECK (getpayloadl, long double, (const long double *)); + +#include "minus-zero.h" +#include "infinity.h" +#include "signed-snan.h" +#include "macros.h" + +#if defined __powerpc__ && LDBL_MANT_DIG == 106 + /* This is PowerPC "double double", a pair of two doubles. NaN is represented + as the corresponding 64-bit IEEE value in the first double; the second is + irrelevant and therefore does not contain a payload. */ +# define PAYLOAD_BITS (DBL_MANT_DIG - 2) +#else +# define PAYLOAD_BITS (LDBL_MANT_DIG - 2) +#endif + +int +main () +{ + long double arg; + long double ret; + + /* Test non-NaN arguments. */ + + arg = 2.71828182845904523536028747135266249776L; + ret = getpayloadl (&arg); + ASSERT (ret == -1.0L); + + arg = -3.1415926535897932384626433832795028842L; + ret = getpayloadl (&arg); + ASSERT (ret == -1.0L); + + arg = 0.0L; + ret = getpayloadl (&arg); + ASSERT (ret == -1.0L); + + arg = minus_zerol; + ret = getpayloadl (&arg); + ASSERT (ret == -1.0L); + + arg = Infinityl (); + ret = getpayloadl (&arg); + ASSERT (ret == -1.0L); + + arg = - Infinityl (); + ret = getpayloadl (&arg); + ASSERT (ret == -1.0L); + + /* Test quiet NaNs. */ + { + int i; + long double p; + + for (i = 0, p = 1.0L; i < PAYLOAD_BITS; i++, p *= 2.0L) + { + ASSERT (setpayloadl (&arg, p) == 0); + ret = getpayloadl (&arg); + ASSERT (ret == p); + /* Test quiet NaNs with sign bit == 1. */ + arg = - arg; + ret = getpayloadl (&arg); + ASSERT (ret == p); + } + + p = 1320699239819071.0L; + ASSERT (setpayloadl (&arg, p) == 0); + ret = getpayloadl (&arg); + ASSERT (ret == p); + } + + /* Test signalling NaNs. */ + { + int i; + long double p; + + for (i = 0, p = 1.0L; i < PAYLOAD_BITS; i++, p *= 2.0L) + { + ASSERT (setpayloadsigl (&arg, p) == 0); + ret = getpayloadl (&arg); + ASSERT (ret == p); + } + + p = 1320699239819071.0L; + ASSERT (setpayloadsigl (&arg, p) == 0); + ret = getpayloadl (&arg); + ASSERT (ret == p); + + /* Test signalling NaNs with sign bit == 1. */ + memory_long_double pos_arg = memory_positive_SNaNl (); + memory_long_double neg_arg = memory_negative_SNaNl (); + long double pos_ret = getpayloadl (&pos_arg.value); + long double neg_ret = getpayloadl (&neg_arg.value); + ASSERT (neg_ret == pos_ret); + } + + return 0; +} -- 2.34.1