ISO C 23 specifies in the (optional, but normative) Annex F also functions for creating signalling NaNs with a given payload. Here is a patch series that implements them.
2024-04-16 Bruno Haible <[email protected]> setpayloadsigl: Add tests. * tests/test-setpayloadsigl.c: New file, based on tests/test-setpayloadl.c. * modules/setpayloadsigl-tests: New file. setpayloadsigl: New module. * lib/math.in.h (setpayloadsigl): New declaration. * lib/setpayloadsigl.c: New file, based on lib/setpayloadl.c. * m4/math_h.m4 (gl_MATH_H): Test whether setpayloadsigl is declared. (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOADSIGL. (gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOADSIGL. * modules/math (Makefile.am): Substitute GNULIB_SETPAYLOADSIGL, HAVE_SETPAYLOADSIGL. * modules/setpayloadsigl: New file. * doc/posix-functions/setpayloadsigl.texi: Mention the new module. 2024-04-16 Bruno Haible <[email protected]> setpayloadsigf: Add tests. * tests/test-setpayloadf.c (PAYLOAD_BITS): New macro. (main): Use it. * tests/test-setpayloadsigf.c: New file, based on tests/test-setpayloadf.c. * modules/setpayloadsigf-tests: New file. setpayloadsigf: New module. * lib/math.in.h (setpayloadsigf): New declaration. * lib/setpayloadsigf.c: New file, based on lib/setpayloadf.c. * m4/math_h.m4 (gl_MATH_H): Test whether setpayloadsigf is declared. (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOADSIGF. (gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOADSIGF. * modules/math (Makefile.am): Substitute GNULIB_SETPAYLOADSIGF, HAVE_SETPAYLOADSIGF. * modules/setpayloadsigf: New file. * doc/posix-functions/setpayloadsigf.texi: Mention the new module. 2024-04-16 Bruno Haible <[email protected]> setpayloadsig: Add tests. * tests/test-setpayload.c (PAYLOAD_BITS): New macro. (main): Use it. * tests/test-setpayloadsig.c: New file, based on tests/test-setpayload.c. * modules/setpayloadsig-tests: New file. setpayloadsig: New module. * lib/math.in.h (setpayloadsig): New declaration. * lib/setpayloadsig.c: New file, based on lib/setpayload.c. * m4/setpayloadsig.m4: New file, based on m4/setpayload.m4. * m4/math_h.m4 (gl_MATH_H): Test whether setpayloadsig is declared. (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOADSIG. (gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOADSIG. * modules/math (Makefile.am): Substitute GNULIB_SETPAYLOADSIG, HAVE_SETPAYLOADSIG. * modules/setpayloadsig: New file. * doc/posix-functions/setpayloadsig.texi: Mention the new module.
>From f9e62b06d50b24b727e2f9940d6c23848070c01c Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Tue, 16 Apr 2024 21:01:17 +0200 Subject: [PATCH 1/6] setpayloadsig: New module. * lib/math.in.h (setpayloadsig): New declaration. * lib/setpayloadsig.c: New file, based on lib/setpayload.c. * m4/setpayloadsig.m4: New file, based on m4/setpayload.m4. * m4/math_h.m4 (gl_MATH_H): Test whether setpayloadsig is declared. (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOADSIG. (gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOADSIG. * modules/math (Makefile.am): Substitute GNULIB_SETPAYLOADSIG, HAVE_SETPAYLOADSIG. * modules/setpayloadsig: New file. * doc/posix-functions/setpayloadsig.texi: Mention the new module. --- ChangeLog | 14 +++++ doc/posix-functions/setpayloadsig.texi | 8 +-- lib/math.in.h | 15 ++++++ lib/setpayloadsig.c | 74 ++++++++++++++++++++++++++ m4/math_h.m4 | 5 +- m4/setpayloadsig.m4 | 63 ++++++++++++++++++++++ modules/math | 2 + modules/setpayloadsig | 36 +++++++++++++ 8 files changed, 212 insertions(+), 5 deletions(-) create mode 100644 lib/setpayloadsig.c create mode 100644 m4/setpayloadsig.m4 create mode 100644 modules/setpayloadsig diff --git a/ChangeLog b/ChangeLog index 7521411127..c4a23adb45 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2024-04-16 Bruno Haible <[email protected]> + + setpayloadsig: New module. + * lib/math.in.h (setpayloadsig): New declaration. + * lib/setpayloadsig.c: New file, based on lib/setpayload.c. + * m4/setpayloadsig.m4: New file, based on m4/setpayload.m4. + * m4/math_h.m4 (gl_MATH_H): Test whether setpayloadsig is declared. + (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOADSIG. + (gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOADSIG. + * modules/math (Makefile.am): Substitute GNULIB_SETPAYLOADSIG, + HAVE_SETPAYLOADSIG. + * modules/setpayloadsig: New file. + * doc/posix-functions/setpayloadsig.texi: Mention the new module. + 2024-04-16 Bruno Haible <[email protected]> setpayloadl: Fix platform-specific bugs. diff --git a/doc/posix-functions/setpayloadsig.texi b/doc/posix-functions/setpayloadsig.texi index 09ef9b86fc..6c40c6039e 100644 --- a/doc/posix-functions/setpayloadsig.texi +++ b/doc/posix-functions/setpayloadsig.texi @@ -10,15 +10,15 @@ @url{https://www.gnu.org/software/libc/manual/html_node/FP-Bit-Twiddling.html}. @end ifnotinfo -Gnulib module: --- +Gnulib module: setpayloadsig 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. @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/math.in.h b/lib/math.in.h index 98da404780..c61e65c423 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -2817,6 +2817,21 @@ _GL_WARN_ON_USE (setpayloadl, "setpayloadl is unportable - " #endif +#if @GNULIB_SETPAYLOADSIG@ +# if !@HAVE_SETPAYLOADSIG@ +_GL_FUNCDECL_SYS (setpayloadsig, int, (double *, double)); +# endif +_GL_CXXALIAS_SYS (setpayloadsig, int, (double *, double)); +_GL_CXXALIASWARN (setpayloadsig); +#elif defined GNULIB_POSIXCHECK +# undef setpayloadsig +# if HAVE_RAW_DECL_SETPAYLOADSIG +_GL_WARN_ON_USE (setpayloadsig, "setpayloadsig is unportable - " + "use gnulib module setpayloadsig for portability"); +# endif +#endif + + #if @GNULIB_TOTALORDERF@ # if @REPLACE_TOTALORDERF@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) diff --git a/lib/setpayloadsig.c b/lib/setpayloadsig.c new file mode 100644 index 0000000000..c336f08c80 --- /dev/null +++ b/lib/setpayloadsig.c @@ -0,0 +1,74 @@ +/* Construct a signalling NaN 'double' with a given payload. + 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> + +#include "signed-snan.h" + +int +setpayloadsig (double *result, double payload) +{ +#if DBL_MANT_DIG == 53 + if ( +# if defined __hppa || defined __mips__ || defined __sh__ + payload >= 0.0 +# else + /* A zero payload is not allowed, because that would denote Infinity. + Cf. snan.h. */ + payload > 0.0 +# endif + && payload < 2251799813685248.0 /* (double) (1ULL << (DBL_MANT_DIG - 2)) */ + && payload == (double) (int64_t) payload) + { + memory_double x = memory_positive_SNaNd (); + uint64_t pl = (int64_t) payload; + uint32_t pl_hi = (uint32_t) (pl >> 32); + uint32_t pl_lo = (uint32_t) pl; + x.word[DBL_EXPBIT0_WORD] = + (x.word[DBL_EXPBIT0_WORD] & ~((1U << (DBL_MANT_DIG - 2 - 32)) - 1)) + | pl_hi; + x.word[DBL_EXPBIT0_WORD + (DBL_EXPBIT0_WORD == 0 ? 1 : -1)] = pl_lo; +# if 0 + *result = x.value; +# else + /* On 32-bit x86 processors, as well as on x86_64 processors with + CC="gcc -mfpmath=387", the evaluation of *x and *y 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 (result, &x.value, sizeof (double)); +# endif + return 0; + } + else + { + *result = 0.0; + return -1; + } +#else +# error "Please port gnulib setpayloadsig.c to your platform!" +#endif +} diff --git a/m4/math_h.m4 b/m4/math_h.m4 index 3dc779160c..0c5ce4f89c 100644 --- a/m4/math_h.m4 +++ b/m4/math_h.m4 @@ -1,5 +1,5 @@ # math_h.m4 -# serial 129 +# serial 130 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, @@ -52,6 +52,7 @@ AC_DEFUN_ONCE([gl_MATH_H] remainder remainderf remainderl rint rintf rintl round roundf roundl setpayload setpayloadf setpayloadl + setpayloadsig sinf sinl sinhf sqrtf sqrtl tanf tanl tanhf totalorder totalorderf totalorderl trunc truncf truncl]) ]) @@ -162,6 +163,7 @@ AC_DEFUN([gl_MATH_H_REQUIRE_DEFAULTS] gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOAD]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADL]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADSIG]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SIGNBIT]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SINF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SINL]) @@ -247,6 +249,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS] HAVE_SETPAYLOAD=1; AC_SUBST([HAVE_SETPAYLOAD]) HAVE_SETPAYLOADF=1; AC_SUBST([HAVE_SETPAYLOADF]) HAVE_SETPAYLOADL=1; AC_SUBST([HAVE_SETPAYLOADL]) + HAVE_SETPAYLOADSIG=1; AC_SUBST([HAVE_SETPAYLOADSIG]) HAVE_SINF=1; AC_SUBST([HAVE_SINF]) HAVE_SINL=1; AC_SUBST([HAVE_SINL]) HAVE_SINHF=1; AC_SUBST([HAVE_SINHF]) diff --git a/m4/setpayloadsig.m4 b/m4/setpayloadsig.m4 new file mode 100644 index 0000000000..a6ff790d4d --- /dev/null +++ b/m4/setpayloadsig.m4 @@ -0,0 +1,63 @@ +# setpayloadsig.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_SETPAYLOADSIGF], +[ + AC_REQUIRE([gl_MATH_H_DEFAULTS]) + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + + gl_MATHFUNC([setpayloadsigf], [int], [(float *, float)]) + if test $gl_cv_func_setpayloadsigf_no_libm != yes \ + && test $gl_cv_func_setpayloadsigf_in_libm != yes; then + HAVE_SETPAYLOADSIGF=0 + fi + if test $HAVE_SETPAYLOADSIGF = 0; then + SETPAYLOADSIGF_LIBM= + fi + AC_SUBST([SETPAYLOADSIGF_LIBM]) +]) + +AC_DEFUN_ONCE([gl_FUNC_SETPAYLOADSIG], +[ + AC_REQUIRE([gl_MATH_H_DEFAULTS]) + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + + gl_MATHFUNC([setpayloadsig], [int], [(double *, double)]) + if test $gl_cv_func_setpayloadsig_no_libm != yes \ + && test $gl_cv_func_setpayloadsig_in_libm != yes; then + HAVE_SETPAYLOADSIG=0 + fi + if test $HAVE_SETPAYLOADSIG = 0; then + SETPAYLOADSIG_LIBM= + fi + AC_SUBST([SETPAYLOADSIG_LIBM]) +]) + +AC_DEFUN([gl_FUNC_SETPAYLOADSIGL], +[ + AC_REQUIRE([gl_MATH_H_DEFAULTS]) + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + AC_REQUIRE([gl_LONG_DOUBLE_VS_DOUBLE]) + + gl_MATHFUNC([setpayloadsigl], [int], [(long double *, long double)]) + if test $gl_cv_func_setpayloadsigl_no_libm != yes \ + && test $gl_cv_func_setpayloadsigl_in_libm != yes; then + HAVE_SETPAYLOADSIGL=0 + fi + if test $HAVE_SETPAYLOADSIGL = 0; then + dnl Find libraries needed to link lib/setpayloadsigl.c. + if test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1; then + AC_REQUIRE([gl_FUNC_SETPAYLOADSIG]) + SETPAYLOADSIGL_LIBM="$SETPAYLOADSIG_LIBM" + else + SETPAYLOADSIGL_LIBM= + fi + dnl Prerequisite of lib/setpayloadsigl.c. + gl_LONG_DOUBLE_EXPONENT_LOCATION + fi + AC_SUBST([SETPAYLOADSIGL_LIBM]) +]) diff --git a/modules/math b/modules/math index 80de39a7f7..722aad91b9 100644 --- a/modules/math +++ b/modules/math @@ -123,6 +123,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's/@''GNULIB_SETPAYLOAD''@/$(GNULIB_SETPAYLOAD)/g' \ -e 's/@''GNULIB_SETPAYLOADF''@/$(GNULIB_SETPAYLOADF)/g' \ -e 's/@''GNULIB_SETPAYLOADL''@/$(GNULIB_SETPAYLOADL)/g' \ + -e 's/@''GNULIB_SETPAYLOADSIG''@/$(GNULIB_SETPAYLOADSIG)/g' \ -e 's/@''GNULIB_SIGNBIT''@/$(GNULIB_SIGNBIT)/g' \ -e 's/@''GNULIB_SINF''@/$(GNULIB_SINF)/g' \ -e 's/@''GNULIB_SINL''@/$(GNULIB_SINL)/g' \ @@ -201,6 +202,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''HAVE_SETPAYLOAD''@|$(HAVE_SETPAYLOAD)|g' \ -e 's|@''HAVE_SETPAYLOADF''@|$(HAVE_SETPAYLOADF)|g' \ -e 's|@''HAVE_SETPAYLOADL''@|$(HAVE_SETPAYLOADL)|g' \ + -e 's|@''HAVE_SETPAYLOADSIG''@|$(HAVE_SETPAYLOADSIG)|g' \ -e 's|@''HAVE_SINF''@|$(HAVE_SINF)|g' \ -e 's|@''HAVE_SINL''@|$(HAVE_SINL)|g' \ -e 's|@''HAVE_SINHF''@|$(HAVE_SINHF)|g' \ diff --git a/modules/setpayloadsig b/modules/setpayloadsig new file mode 100644 index 0000000000..27bb3a614e --- /dev/null +++ b/modules/setpayloadsig @@ -0,0 +1,36 @@ +Description: +setpayloadsig function: construct a signalling NaN with a given payload + +Files: +lib/setpayloadsig.c +m4/mathfunc.m4 +m4/setpayloadsig.m4 + +Depends-on: +math +extensions +float [test $HAVE_SETPAYLOADSIG = 0] +stdint [test $HAVE_SETPAYLOADSIG = 0] +signed-snan [test $HAVE_SETPAYLOADSIG = 0] + +configure.ac: +gl_FUNC_SETPAYLOADSIG +gl_CONDITIONAL([GL_COND_OBJ_SETPAYLOADSIG], [test $HAVE_SETPAYLOADSIG = 0]) +gl_MATH_MODULE_INDICATOR([setpayloadsig]) + +Makefile.am: +if GL_COND_OBJ_SETPAYLOADSIG +lib_SOURCES += setpayloadsig.c +endif + +Include: +<math.h> + +Link: +$(SETPAYLOADSIG_LIBM) + +License: +LGPL + +Maintainer: +all -- 2.34.1
>From 7daa10a173989f84cad5fe027d5ca61f31ff0ab2 Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Tue, 16 Apr 2024 21:06:20 +0200 Subject: [PATCH 2/6] setpayloadsig: Add tests. * tests/test-setpayload.c (PAYLOAD_BITS): New macro. (main): Use it. * tests/test-setpayloadsig.c: New file, based on tests/test-setpayload.c. * modules/setpayloadsig-tests: New file. --- ChangeLog | 7 +++ modules/setpayloadsig-tests | 15 +++++++ tests/test-setpayload.c | 4 +- tests/test-setpayloadsig.c | 88 +++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 modules/setpayloadsig-tests create mode 100644 tests/test-setpayloadsig.c diff --git a/ChangeLog b/ChangeLog index c4a23adb45..ed599bd255 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2024-04-16 Bruno Haible <[email protected]> + setpayloadsig: Add tests. + * tests/test-setpayload.c (PAYLOAD_BITS): New macro. + (main): Use it. + * tests/test-setpayloadsig.c: New file, based on + tests/test-setpayload.c. + * modules/setpayloadsig-tests: New file. + setpayloadsig: New module. * lib/math.in.h (setpayloadsig): New declaration. * lib/setpayloadsig.c: New file, based on lib/setpayload.c. diff --git a/modules/setpayloadsig-tests b/modules/setpayloadsig-tests new file mode 100644 index 0000000000..3c7845892d --- /dev/null +++ b/modules/setpayloadsig-tests @@ -0,0 +1,15 @@ +Files: +tests/test-setpayloadsig.c +tests/infinity.h +tests/signature.h +tests/macros.h + +Depends-on: +isnand-nolibm + +configure.ac: + +Makefile.am: +TESTS += test-setpayloadsig +check_PROGRAMS += test-setpayloadsig +test_setpayloadsig_LDADD = $(LDADD) @SETPAYLOADSIG_LIBM@ diff --git a/tests/test-setpayload.c b/tests/test-setpayload.c index d539b75ffc..a9976f2842 100644 --- a/tests/test-setpayload.c +++ b/tests/test-setpayload.c @@ -26,6 +26,8 @@ SIGNATURE_CHECK (setpayload, int, (double *, double)); #include "isnand-nolibm.h" #include "macros.h" +#define PAYLOAD_BITS (53 - 2) /* = (DBL_MANT_DIG - 2) */ + int main () { @@ -34,7 +36,7 @@ main () { /* Test valid payloads. */ - for (i = 0, p = 1.0; i < 53 - 2; i++, p *= 2.0) + for (i = 0, p = 1.0; i < PAYLOAD_BITS; i++, p *= 2.0) { int ret; double x; diff --git a/tests/test-setpayloadsig.c b/tests/test-setpayloadsig.c new file mode 100644 index 0000000000..c8f9925841 --- /dev/null +++ b/tests/test-setpayloadsig.c @@ -0,0 +1,88 @@ +/* Test setpayloadsig. + 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 (setpayloadsig, int, (double *, double)); + +#include "infinity.h" +#include "isnand-nolibm.h" +#include "macros.h" + +#define PAYLOAD_BITS (53 - 2) /* = (DBL_MANT_DIG - 2) */ + +int +main () +{ + int i; + double p; + + { + /* Test valid payloads. */ + for (i = 0, p = 1.0; i < PAYLOAD_BITS; i++, p *= 2.0) + { + int ret; + double x; + + ret = setpayloadsig (&x, p); + ASSERT (ret == 0); + ASSERT (isnand (x)); + } + /* Test out-of-range payload. */ + int ret; + double x; + + ret = setpayloadsig (&x, p); + ASSERT (ret != 0); + ASSERT (x == 0.0); + } + + /* Test infinite payload. */ + { + int ret; + double x; + + ret = setpayloadsig (&x, Infinityd ()); + ASSERT (ret != 0); + ASSERT (x == 0.0); + } + + /* Test negative payload. */ + { + int ret; + double x; + + ret = setpayloadsig (&x, -1.0); + ASSERT (ret != 0); + ASSERT (x == 0.0); + } + + /* Test fractional payload. */ + { + int ret; + double x; + + ret = setpayloadsig (&x, 1.4); + ASSERT (ret != 0); + ASSERT (x == 0.0); + } + + return 0; +} -- 2.34.1
>From 8cf6f8cdd3077e475cbe1e1b3252ac9bc90a4cf5 Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Tue, 16 Apr 2024 21:12:39 +0200 Subject: [PATCH 3/6] setpayloadsigf: New module. * lib/math.in.h (setpayloadsigf): New declaration. * lib/setpayloadsigf.c: New file, based on lib/setpayloadf.c. * m4/math_h.m4 (gl_MATH_H): Test whether setpayloadsigf is declared. (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOADSIGF. (gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOADSIGF. * modules/math (Makefile.am): Substitute GNULIB_SETPAYLOADSIGF, HAVE_SETPAYLOADSIGF. * modules/setpayloadsigf: New file. * doc/posix-functions/setpayloadsigf.texi: Mention the new module. --- ChangeLog | 13 +++++ doc/posix-functions/setpayloadsigf.texi | 8 +-- lib/math.in.h | 14 +++++ lib/setpayloadsigf.c | 69 +++++++++++++++++++++++++ m4/math_h.m4 | 6 ++- modules/math | 2 + modules/setpayloadsigf | 36 +++++++++++++ 7 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 lib/setpayloadsigf.c create mode 100644 modules/setpayloadsigf diff --git a/ChangeLog b/ChangeLog index ed599bd255..238b032d49 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2024-04-16 Bruno Haible <[email protected]> + + setpayloadsigf: New module. + * lib/math.in.h (setpayloadsigf): New declaration. + * lib/setpayloadsigf.c: New file, based on lib/setpayloadf.c. + * m4/math_h.m4 (gl_MATH_H): Test whether setpayloadsigf is declared. + (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOADSIGF. + (gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOADSIGF. + * modules/math (Makefile.am): Substitute GNULIB_SETPAYLOADSIGF, + HAVE_SETPAYLOADSIGF. + * modules/setpayloadsigf: New file. + * doc/posix-functions/setpayloadsigf.texi: Mention the new module. + 2024-04-16 Bruno Haible <[email protected]> setpayloadsig: Add tests. diff --git a/doc/posix-functions/setpayloadsigf.texi b/doc/posix-functions/setpayloadsigf.texi index 6bb4dc9aef..22f09ae268 100644 --- a/doc/posix-functions/setpayloadsigf.texi +++ b/doc/posix-functions/setpayloadsigf.texi @@ -10,15 +10,15 @@ @url{https://www.gnu.org/software/libc/manual/html_node/FP-Bit-Twiddling.html}. @end ifnotinfo -Gnulib module: --- +Gnulib module: setpayloadsigf 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. @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/math.in.h b/lib/math.in.h index c61e65c423..416530e050 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -2817,6 +2817,20 @@ _GL_WARN_ON_USE (setpayloadl, "setpayloadl is unportable - " #endif +#if @GNULIB_SETPAYLOADSIGF@ +# if !@HAVE_SETPAYLOADSIGF@ +_GL_FUNCDECL_SYS (setpayloadsigf, int, (float *, float)); +# endif +_GL_CXXALIAS_SYS (setpayloadsigf, int, (float *, float)); +_GL_CXXALIASWARN (setpayloadsigf); +#elif defined GNULIB_POSIXCHECK +# undef setpayloadsigf +# if HAVE_RAW_DECL_SETPAYLOADSIGF +_GL_WARN_ON_USE (setpayloadsigf, "setpayloadsigf is unportable - " + "use gnulib module setpayloadsigf for portability"); +# endif +#endif + #if @GNULIB_SETPAYLOADSIG@ # if !@HAVE_SETPAYLOADSIG@ _GL_FUNCDECL_SYS (setpayloadsig, int, (double *, double)); diff --git a/lib/setpayloadsigf.c b/lib/setpayloadsigf.c new file mode 100644 index 0000000000..0f41f9f3df --- /dev/null +++ b/lib/setpayloadsigf.c @@ -0,0 +1,69 @@ +/* Construct a signalling NaN 'float' with a given payload. + 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> + +#include "signed-snan.h" + +int +setpayloadsigf (float *result, float payload) +{ +#if FLT_MANT_DIG == 24 + if ( +# if defined __hppa || defined __mips__ || defined __sh__ + payload >= 0.0f +# else + /* A zero payload is not allowed, because that would denote Infinity. + Cf. snan.h. */ + payload > 0.0f +# endif + && payload < 4194304.0f /* (float) (1U << (FLT_MANT_DIG - 2)) */ + && payload == (float) (int32_t) payload) + { + memory_float x = memory_positive_SNaNf (); + x.word[0] = (x.word[0] & ~((1U << (FLT_MANT_DIG - 2)) - 1)) + | (int32_t) payload; +# if 0 + *result = x.value; +# else + /* On 32-bit x86 processors, as well as on x86_64 processors with + CC="gcc -mfpmath=387", the evaluation of *x and *y 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 (result, &x.value, sizeof (float)); +# endif + return 0; + } + else + { + *result = 0.0f; + return -1; + } +#else +# error "Please port gnulib setpayloadsigf.c to your platform!" +#endif +} diff --git a/m4/math_h.m4 b/m4/math_h.m4 index 0c5ce4f89c..f458464a2e 100644 --- a/m4/math_h.m4 +++ b/m4/math_h.m4 @@ -1,5 +1,5 @@ # math_h.m4 -# serial 130 +# serial 131 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, @@ -52,7 +52,7 @@ AC_DEFUN_ONCE([gl_MATH_H] remainder remainderf remainderl rint rintf rintl round roundf roundl setpayload setpayloadf setpayloadl - setpayloadsig + setpayloadsig setpayloadsigf sinf sinl sinhf sqrtf sqrtl tanf tanl tanhf totalorder totalorderf totalorderl trunc truncf truncl]) ]) @@ -164,6 +164,7 @@ AC_DEFUN([gl_MATH_H_REQUIRE_DEFAULTS] gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADL]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADSIG]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADSIGF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SIGNBIT]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SINF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SINL]) @@ -250,6 +251,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS] HAVE_SETPAYLOADF=1; AC_SUBST([HAVE_SETPAYLOADF]) HAVE_SETPAYLOADL=1; AC_SUBST([HAVE_SETPAYLOADL]) HAVE_SETPAYLOADSIG=1; AC_SUBST([HAVE_SETPAYLOADSIG]) + HAVE_SETPAYLOADSIGF=1; AC_SUBST([HAVE_SETPAYLOADSIGF]) HAVE_SINF=1; AC_SUBST([HAVE_SINF]) HAVE_SINL=1; AC_SUBST([HAVE_SINL]) HAVE_SINHF=1; AC_SUBST([HAVE_SINHF]) diff --git a/modules/math b/modules/math index 722aad91b9..b1a2a94e4c 100644 --- a/modules/math +++ b/modules/math @@ -124,6 +124,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's/@''GNULIB_SETPAYLOADF''@/$(GNULIB_SETPAYLOADF)/g' \ -e 's/@''GNULIB_SETPAYLOADL''@/$(GNULIB_SETPAYLOADL)/g' \ -e 's/@''GNULIB_SETPAYLOADSIG''@/$(GNULIB_SETPAYLOADSIG)/g' \ + -e 's/@''GNULIB_SETPAYLOADSIGF''@/$(GNULIB_SETPAYLOADSIGF)/g' \ -e 's/@''GNULIB_SIGNBIT''@/$(GNULIB_SIGNBIT)/g' \ -e 's/@''GNULIB_SINF''@/$(GNULIB_SINF)/g' \ -e 's/@''GNULIB_SINL''@/$(GNULIB_SINL)/g' \ @@ -203,6 +204,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''HAVE_SETPAYLOADF''@|$(HAVE_SETPAYLOADF)|g' \ -e 's|@''HAVE_SETPAYLOADL''@|$(HAVE_SETPAYLOADL)|g' \ -e 's|@''HAVE_SETPAYLOADSIG''@|$(HAVE_SETPAYLOADSIG)|g' \ + -e 's|@''HAVE_SETPAYLOADSIGF''@|$(HAVE_SETPAYLOADSIGF)|g' \ -e 's|@''HAVE_SINF''@|$(HAVE_SINF)|g' \ -e 's|@''HAVE_SINL''@|$(HAVE_SINL)|g' \ -e 's|@''HAVE_SINHF''@|$(HAVE_SINHF)|g' \ diff --git a/modules/setpayloadsigf b/modules/setpayloadsigf new file mode 100644 index 0000000000..1807e9ada3 --- /dev/null +++ b/modules/setpayloadsigf @@ -0,0 +1,36 @@ +Description: +setpayloadsigf function: construct a signalling NaN with a given payload + +Files: +lib/setpayloadsigf.c +m4/mathfunc.m4 +m4/setpayloadsig.m4 + +Depends-on: +math +extensions +float [test $HAVE_SETPAYLOADSIGF = 0] +stdint [test $HAVE_SETPAYLOADSIGF = 0] +signed-snan [test $HAVE_SETPAYLOADSIGF = 0] + +configure.ac: +gl_FUNC_SETPAYLOADSIGF +gl_CONDITIONAL([GL_COND_OBJ_SETPAYLOADSIGF], [test $HAVE_SETPAYLOADSIGF = 0]) +gl_MATH_MODULE_INDICATOR([setpayloadsigf]) + +Makefile.am: +if GL_COND_OBJ_SETPAYLOADSIGF +lib_SOURCES += setpayloadsigf.c +endif + +Include: +<math.h> + +Link: +$(SETPAYLOADSIGF_LIBM) + +License: +LGPL + +Maintainer: +all -- 2.34.1
>From 86ddf2e74f8c097382dff72b99e6a71e5425f51e Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Tue, 16 Apr 2024 21:15:16 +0200 Subject: [PATCH 4/6] setpayloadsigf: Add tests. * tests/test-setpayloadf.c (PAYLOAD_BITS): New macro. (main): Use it. * tests/test-setpayloadsigf.c: New file, based on tests/test-setpayloadf.c. * modules/setpayloadsigf-tests: New file. --- ChangeLog | 7 +++ modules/setpayloadsigf-tests | 15 ++++++ tests/test-setpayloadf.c | 4 +- tests/test-setpayloadsigf.c | 88 ++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 modules/setpayloadsigf-tests create mode 100644 tests/test-setpayloadsigf.c diff --git a/ChangeLog b/ChangeLog index 238b032d49..ff58ee26b3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2024-04-16 Bruno Haible <[email protected]> + setpayloadsigf: Add tests. + * tests/test-setpayloadf.c (PAYLOAD_BITS): New macro. + (main): Use it. + * tests/test-setpayloadsigf.c: New file, based on + tests/test-setpayloadf.c. + * modules/setpayloadsigf-tests: New file. + setpayloadsigf: New module. * lib/math.in.h (setpayloadsigf): New declaration. * lib/setpayloadsigf.c: New file, based on lib/setpayloadf.c. diff --git a/modules/setpayloadsigf-tests b/modules/setpayloadsigf-tests new file mode 100644 index 0000000000..7f9baefea1 --- /dev/null +++ b/modules/setpayloadsigf-tests @@ -0,0 +1,15 @@ +Files: +tests/test-setpayloadsigf.c +tests/infinity.h +tests/signature.h +tests/macros.h + +Depends-on: +isnanf-nolibm + +configure.ac: + +Makefile.am: +TESTS += test-setpayloadsigf +check_PROGRAMS += test-setpayloadsigf +test_setpayloadsigf_LDADD = $(LDADD) @SETPAYLOADSIGF_LIBM@ diff --git a/tests/test-setpayloadf.c b/tests/test-setpayloadf.c index aa790343ae..af8af962ef 100644 --- a/tests/test-setpayloadf.c +++ b/tests/test-setpayloadf.c @@ -26,6 +26,8 @@ SIGNATURE_CHECK (setpayloadf, int, (float *, float)); #include "isnanf-nolibm.h" #include "macros.h" +#define PAYLOAD_BITS (24 - 2) /* = (FLT_MANT_DIG - 2) */ + int main () { @@ -34,7 +36,7 @@ main () { /* Test valid payloads. */ - for (i = 0, p = 1.0f; i < 24 - 2; i++, p *= 2.0f) + for (i = 0, p = 1.0f; i < PAYLOAD_BITS; i++, p *= 2.0f) { int ret; float x; diff --git a/tests/test-setpayloadsigf.c b/tests/test-setpayloadsigf.c new file mode 100644 index 0000000000..d95d497e5f --- /dev/null +++ b/tests/test-setpayloadsigf.c @@ -0,0 +1,88 @@ +/* Test setpayloadsigf. + 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 (setpayloadsigf, int, (float *, float)); + +#include "infinity.h" +#include "isnanf-nolibm.h" +#include "macros.h" + +#define PAYLOAD_BITS (24 - 2) /* = (FLT_MANT_DIG - 2) */ + +int +main () +{ + int i; + float p; + + { + /* Test valid payloads. */ + for (i = 0, p = 1.0f; i < PAYLOAD_BITS; i++, p *= 2.0f) + { + int ret; + float x; + + ret = setpayloadsigf (&x, p); + ASSERT (ret == 0); + ASSERT (isnanf (x)); + } + /* Test out-of-range payload. */ + int ret; + float x; + + ret = setpayloadsigf (&x, p); + ASSERT (ret != 0); + ASSERT (x == 0.0f); + } + + /* Test infinite payload. */ + { + int ret; + float x; + + ret = setpayloadsigf (&x, Infinityf ()); + ASSERT (ret != 0); + ASSERT (x == 0.0f); + } + + /* Test negative payload. */ + { + int ret; + float x; + + ret = setpayloadsigf (&x, -1.0f); + ASSERT (ret != 0); + ASSERT (x == 0.0f); + } + + /* Test fractional payload. */ + { + int ret; + float x; + + ret = setpayloadsigf (&x, 1.4f); + ASSERT (ret != 0); + ASSERT (x == 0.0f); + } + + return 0; +} -- 2.34.1
>From 7a4a7fd18d3bfdc997ec8ac4d17b4064e04bde61 Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Tue, 16 Apr 2024 21:28:42 +0200 Subject: [PATCH 5/6] setpayloadsigl: New module. * lib/math.in.h (setpayloadsigl): New declaration. * lib/setpayloadsigl.c: New file, based on lib/setpayloadl.c. * m4/math_h.m4 (gl_MATH_H): Test whether setpayloadsigl is declared. (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOADSIGL. (gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOADSIGL. * modules/math (Makefile.am): Substitute GNULIB_SETPAYLOADSIGL, HAVE_SETPAYLOADSIGL. * modules/setpayloadsigl: New file. * doc/posix-functions/setpayloadsigl.texi: Mention the new module. --- ChangeLog | 13 +++ doc/posix-functions/setpayloadsigl.texi | 8 +- lib/math.in.h | 14 +++ lib/setpayloadsigl.c | 129 ++++++++++++++++++++++++ m4/math_h.m4 | 6 +- modules/math | 2 + modules/setpayloadsigl | 38 +++++++ 7 files changed, 204 insertions(+), 6 deletions(-) create mode 100644 lib/setpayloadsigl.c create mode 100644 modules/setpayloadsigl diff --git a/ChangeLog b/ChangeLog index ff58ee26b3..e862623d6c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2024-04-16 Bruno Haible <[email protected]> + + setpayloadsigl: New module. + * lib/math.in.h (setpayloadsigl): New declaration. + * lib/setpayloadsigl.c: New file, based on lib/setpayloadl.c. + * m4/math_h.m4 (gl_MATH_H): Test whether setpayloadsigl is declared. + (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOADSIGL. + (gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOADSIGL. + * modules/math (Makefile.am): Substitute GNULIB_SETPAYLOADSIGL, + HAVE_SETPAYLOADSIGL. + * modules/setpayloadsigl: New file. + * doc/posix-functions/setpayloadsigl.texi: Mention the new module. + 2024-04-16 Bruno Haible <[email protected]> setpayloadsigf: Add tests. diff --git a/doc/posix-functions/setpayloadsigl.texi b/doc/posix-functions/setpayloadsigl.texi index f170f7090f..9d8dee189b 100644 --- a/doc/posix-functions/setpayloadsigl.texi +++ b/doc/posix-functions/setpayloadsigl.texi @@ -10,15 +10,15 @@ @url{https://www.gnu.org/software/libc/manual/html_node/FP-Bit-Twiddling.html}. @end ifnotinfo -Gnulib module: --- +Gnulib module: setpayloadsigl 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. @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/math.in.h b/lib/math.in.h index 416530e050..7bb7976b61 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -2845,6 +2845,20 @@ _GL_WARN_ON_USE (setpayloadsig, "setpayloadsig is unportable - " # endif #endif +#if @GNULIB_SETPAYLOADSIGL@ +# if !@HAVE_SETPAYLOADSIGL@ +_GL_FUNCDECL_SYS (setpayloadsigl, int, (long double *, long double)); +# endif +_GL_CXXALIAS_SYS (setpayloadsigl, int, (long double *, long double)); +_GL_CXXALIASWARN (setpayloadsigl); +#elif defined GNULIB_POSIXCHECK +# undef setpayloadsigl +# if HAVE_RAW_DECL_SETPAYLOADSIGL +_GL_WARN_ON_USE (setpayloadsigl, "setpayloadsigl is unportable - " + "use gnulib module setpayloadsigl for portability"); +# endif +#endif + #if @GNULIB_TOTALORDERF@ # if @REPLACE_TOTALORDERF@ diff --git a/lib/setpayloadsigl.c b/lib/setpayloadsigl.c new file mode 100644 index 0000000000..5cfe3cb783 --- /dev/null +++ b/lib/setpayloadsigl.c @@ -0,0 +1,129 @@ +/* Construct a signalling NaN 'long double' with a given payload. + 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 + +int +setpayloadsigl (long double *result, long double payload) +{ + return setpayloadsig ((double *) result, payload); +} + +#else + +# include <float.h> +# include <stdint.h> + +# include "signed-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))) + +int +setpayloadsigl (long double *result, long double payload) +{ +# if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 106 || LDBL_MANT_DIG == 113) \ + && defined LDBL_EXPBIT0_WORD && defined LDBL_EXPBIT0_BIT + if ( +# if defined __hppa || defined __mips__ || defined __sh__ + payload >= 0.0L +# else + /* A zero payload is not allowed, because that would denote Infinity. + Cf. snan.h. */ + payload > 0.0L +# endif +# if LDBL_MANT_DIG == 64 /* on i386, x86_64, ia64, m68k */ + && payload < 4611686018427387904.0L /* exp2l (LDBL_MANT_DIG - 2) */ + && payload == (long double) (int64_t) payload +# endif +# if LDBL_MANT_DIG == 106 /* on powerpc, powerpc64, powerpc64le */ + && payload < 2251799813685248.0L /* exp2l (DBL_MANT_DIG - 2) */ + && payload == (long double) (int64_t) payload +# endif +# if LDBL_MANT_DIG == 113 /* on alpha, arm64, loongarch64, mips64, riscv64, s390x, sparc64 */ + && payload < 2596148429267413814265248164610048.0L /* exp2l (LDBL_MANT_DIG - 2) */ + && payload == +(+(payload + TWO_LDBL_MANT_DIG) - TWO_LDBL_MANT_DIG) +# endif + ) + { + memory_long_double x = memory_positive_SNaNl (); + +# if LDBL_MANT_DIG == 64 /* on i386, x86_64, ia64, m68k */ + uint64_t pl = (int64_t) payload; +# if LDBL_EXPBIT0_WORD == 2 && LDBL_EXPBIT0_BIT == 0 /* on i386, x86_64, ia64 */ + x.word[1] = (x.word[1] & 0xC0000000U) | (uint32_t) (pl >> 32); + x.word[0] = (uint32_t) pl; +# elif LDBL_EXPBIT0_WORD == 0 && LDBL_EXPBIT0_BIT == 16 /* on m68k */ + x.word[1] = (x.word[1] & 0xC0000000U) | (uint32_t) (pl >> 32); + x.word[2] = (uint32_t) pl; +# else +# error "Please port gnulib setpayloadsigl.c to your platform!" +# endif +# endif +# if LDBL_MANT_DIG == 106 /* on powerpc, powerpc64, powerpc64le */ + uint64_t pl = (int64_t) payload; +# if LDBL_EXPBIT0_BIT == 20 + uint32_t pl_hi = (uint32_t) (pl >> 32); + uint32_t pl_lo = (uint32_t) pl; + x.word[LDBL_EXPBIT0_WORD] = (x.word[LDBL_EXPBIT0_WORD] & 0xFFF80000U) + | pl_hi; + x.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 1 : -1)] = pl_lo; +# else +# error "Please port gnulib setpayloadsigl.c to your platform!" +# endif +# 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 = payload + TWO_LDBL_MANT_DIG; + x.word[LDBL_EXPBIT0_WORD] = (x.word[LDBL_EXPBIT0_WORD] & 0xFFFF8000U) + | (pl.word[LDBL_EXPBIT0_WORD] & 0x00007FFFU); + x.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 1 : -1)] = + pl.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 1 : -1)]; + x.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 2 : -2)] = + pl.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 2 : -2)]; + x.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 3 : -3)] = + pl.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 3 : -3)]; +# else +# error "Please port gnulib setpayloadsigl.c to your platform!" +# endif +# endif + + *result = x.value; + return 0; + } + else + { + *result = 0.0L; + return -1; + } +# else +# error "Please port gnulib setpayloadsigl.c to your platform!" +# endif +} + +#endif diff --git a/m4/math_h.m4 b/m4/math_h.m4 index f458464a2e..7bcacf6959 100644 --- a/m4/math_h.m4 +++ b/m4/math_h.m4 @@ -1,5 +1,5 @@ # math_h.m4 -# serial 131 +# serial 132 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, @@ -52,7 +52,7 @@ AC_DEFUN_ONCE([gl_MATH_H] remainder remainderf remainderl rint rintf rintl round roundf roundl setpayload setpayloadf setpayloadl - setpayloadsig setpayloadsigf + setpayloadsig setpayloadsigf setpayloadsigl sinf sinl sinhf sqrtf sqrtl tanf tanl tanhf totalorder totalorderf totalorderl trunc truncf truncl]) ]) @@ -165,6 +165,7 @@ AC_DEFUN([gl_MATH_H_REQUIRE_DEFAULTS] gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADL]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADSIG]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADSIGF]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADSIGL]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SIGNBIT]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SINF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SINL]) @@ -252,6 +253,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS] HAVE_SETPAYLOADL=1; AC_SUBST([HAVE_SETPAYLOADL]) HAVE_SETPAYLOADSIG=1; AC_SUBST([HAVE_SETPAYLOADSIG]) HAVE_SETPAYLOADSIGF=1; AC_SUBST([HAVE_SETPAYLOADSIGF]) + HAVE_SETPAYLOADSIGL=1; AC_SUBST([HAVE_SETPAYLOADSIGL]) HAVE_SINF=1; AC_SUBST([HAVE_SINF]) HAVE_SINL=1; AC_SUBST([HAVE_SINL]) HAVE_SINHF=1; AC_SUBST([HAVE_SINHF]) diff --git a/modules/math b/modules/math index b1a2a94e4c..70baab7586 100644 --- a/modules/math +++ b/modules/math @@ -125,6 +125,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's/@''GNULIB_SETPAYLOADL''@/$(GNULIB_SETPAYLOADL)/g' \ -e 's/@''GNULIB_SETPAYLOADSIG''@/$(GNULIB_SETPAYLOADSIG)/g' \ -e 's/@''GNULIB_SETPAYLOADSIGF''@/$(GNULIB_SETPAYLOADSIGF)/g' \ + -e 's/@''GNULIB_SETPAYLOADSIGL''@/$(GNULIB_SETPAYLOADSIGL)/g' \ -e 's/@''GNULIB_SIGNBIT''@/$(GNULIB_SIGNBIT)/g' \ -e 's/@''GNULIB_SINF''@/$(GNULIB_SINF)/g' \ -e 's/@''GNULIB_SINL''@/$(GNULIB_SINL)/g' \ @@ -205,6 +206,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''HAVE_SETPAYLOADL''@|$(HAVE_SETPAYLOADL)|g' \ -e 's|@''HAVE_SETPAYLOADSIG''@|$(HAVE_SETPAYLOADSIG)|g' \ -e 's|@''HAVE_SETPAYLOADSIGF''@|$(HAVE_SETPAYLOADSIGF)|g' \ + -e 's|@''HAVE_SETPAYLOADSIGL''@|$(HAVE_SETPAYLOADSIGL)|g' \ -e 's|@''HAVE_SINF''@|$(HAVE_SINF)|g' \ -e 's|@''HAVE_SINL''@|$(HAVE_SINL)|g' \ -e 's|@''HAVE_SINHF''@|$(HAVE_SINHF)|g' \ diff --git a/modules/setpayloadsigl b/modules/setpayloadsigl new file mode 100644 index 0000000000..deadba06af --- /dev/null +++ b/modules/setpayloadsigl @@ -0,0 +1,38 @@ +Description: +setpayloadsigl function: construct a signalling NaN with a given payload + +Files: +lib/setpayloadsigl.c +m4/mathfunc.m4 +m4/setpayloadsig.m4 +m4/exponentl.m4 + +Depends-on: +math +extensions +setpayloadsig [test $HAVE_SETPAYLOADSIGL = 0 && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1] +float [test $HAVE_SETPAYLOADSIGL = 0 && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] +stdint [test $HAVE_SETPAYLOADSIGL = 0 && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] +signed-snan [test $HAVE_SETPAYLOADSIGL = 0 && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] + +configure.ac: +gl_FUNC_SETPAYLOADSIGL +gl_CONDITIONAL([GL_COND_OBJ_SETPAYLOADSIGL], [test $HAVE_SETPAYLOADSIGL = 0]) +gl_MATH_MODULE_INDICATOR([setpayloadsigl]) + +Makefile.am: +if GL_COND_OBJ_SETPAYLOADSIGL +lib_SOURCES += setpayloadsigl.c +endif + +Include: +<math.h> + +Link: +$(SETPAYLOADSIGL_LIBM) + +License: +LGPL + +Maintainer: +all -- 2.34.1
>From e135884192c6ab4eb3cc1de853a571291aa9ae22 Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Tue, 16 Apr 2024 21:29:16 +0200 Subject: [PATCH 6/6] setpayloadsigl: Add tests. * tests/test-setpayloadsigl.c: New file, based on tests/test-setpayloadl.c. * modules/setpayloadsigl-tests: New file. --- ChangeLog | 5 ++ modules/setpayloadsigl-tests | 15 ++++++ tests/test-setpayloadsigl.c | 97 ++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 modules/setpayloadsigl-tests create mode 100644 tests/test-setpayloadsigl.c diff --git a/ChangeLog b/ChangeLog index e862623d6c..6d4d37cca8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2024-04-16 Bruno Haible <[email protected]> + setpayloadsigl: Add tests. + * tests/test-setpayloadsigl.c: New file, based on + tests/test-setpayloadl.c. + * modules/setpayloadsigl-tests: New file. + setpayloadsigl: New module. * lib/math.in.h (setpayloadsigl): New declaration. * lib/setpayloadsigl.c: New file, based on lib/setpayloadl.c. diff --git a/modules/setpayloadsigl-tests b/modules/setpayloadsigl-tests new file mode 100644 index 0000000000..84073f96ad --- /dev/null +++ b/modules/setpayloadsigl-tests @@ -0,0 +1,15 @@ +Files: +tests/test-setpayloadsigl.c +tests/infinity.h +tests/signature.h +tests/macros.h + +Depends-on: +isnanl-nolibm + +configure.ac: + +Makefile.am: +TESTS += test-setpayloadsigl +check_PROGRAMS += test-setpayloadsigl +test_setpayloadsigl_LDADD = $(LDADD) @SETPAYLOADSIGL_LIBM@ diff --git a/tests/test-setpayloadsigl.c b/tests/test-setpayloadsigl.c new file mode 100644 index 0000000000..13f1eba393 --- /dev/null +++ b/tests/test-setpayloadsigl.c @@ -0,0 +1,97 @@ +/* Test setpayloadsigl. + 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 (setpayloadsigl, int, (long double *, long double)); + +#include <float.h> + +#include "infinity.h" +#include "isnanl-nolibm.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 () +{ + int i; + long double p; + + { + /* Test valid payloads. */ + for (i = 0, p = 1.0L; i < PAYLOAD_BITS; i++, p *= 2.0L) + { + int ret; + long double x; + + ret = setpayloadsigl (&x, p); + ASSERT (ret == 0); + ASSERT (isnanl (x)); + } + /* Test out-of-range payload. */ + int ret; + long double x; + + ret = setpayloadsigl (&x, p); + ASSERT (ret != 0); + ASSERT (x == 0.0L); + } + + /* Test infinite payload. */ + { + int ret; + long double x; + + ret = setpayloadsigl (&x, Infinityl ()); + ASSERT (ret != 0); + ASSERT (x == 0.0L); + } + + /* Test negative payload. */ + { + int ret; + long double x; + + ret = setpayloadsigl (&x, -1.0L); + ASSERT (ret != 0); + ASSERT (x == 0.0L); + } + + /* Test fractional payload. */ + { + int ret; + long double x; + + ret = setpayloadsigl (&x, 1.4L); + ASSERT (ret != 0); + ASSERT (x == 0.0L); + } + + return 0; +} -- 2.34.1
