ISO C 23 specifies in the (optional, but normative) Annex F functions
for creating NaNs with payload.

glibc has these functions already since 2017. But portable programs
cannot use them, if Gnulib does not implement them as well.

Therefore, this set of patches implements them.


2024-04-16  Bruno Haible  <br...@clisp.org>

        setpayloadl: Add tests.
        * tests/test-setpayloadl.c: New file.
        * modules/setpayloadl-tests: New file.

        setpayloadl: New module.
        * lib/math.in.h (setpayloadl): New declaration.
        * lib/setpayloadl.c: New file.
        * m4/math_h.m4 (gl_MATH_H): Test whether setpayloadl is declared.
        (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOADL.
        (gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOADL.
        * modules/math (Makefile.am): Substitute GNULIB_SETPAYLOADL,
        HAVE_SETPAYLOADL.
        * modules/setpayloadl: New file.
        * doc/posix-functions/setpayloadl.texi: Mention the new module.

2024-04-16  Bruno Haible  <br...@clisp.org>

        setpayloadf: Add tests.
        * tests/test-setpayloadf.c: New file.
        * modules/setpayloadf-tests: New file.

        setpayloadf: New module.
        * lib/math.in.h (setpayloadf): New declaration.
        * lib/setpayloadf.c: New file.
        * m4/math_h.m4 (gl_MATH_H): Test whether setpayloadf is declared.
        (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOADF.
        (gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOADF.
        * modules/math (Makefile.am): Substitute GNULIB_SETPAYLOADF,
        HAVE_SETPAYLOADF.
        * modules/setpayloadf: New file.
        * doc/posix-functions/setpayloadf.texi: Mention the new module.

2024-04-16  Bruno Haible  <br...@clisp.org>

        setpayload: Add tests.
        * tests/test-setpayload.c: New file.
        * modules/setpayload-tests: New file.

        setpayload: New module.
        * lib/math.in.h (setpayload): New declaration.
        * lib/setpayload.c: New file.
        * m4/setpayload.m4: New file.
        * m4/math_h.m4 (gl_MATH_H): Test whether setpayload is declared.
        (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOAD.
        (gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOAD.
        * modules/math (Makefile.am): Substitute GNULIB_SETPAYLOAD,
        HAVE_SETPAYLOAD.
        * modules/setpayload: New file.
        * doc/posix-functions/setpayload.texi: Mention the new module.

>From e53309da10a1ec7d5b47dbd9f561763f17f74fb8 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Tue, 16 Apr 2024 14:25:27 +0200
Subject: [PATCH 1/6] setpayload: New module.

* lib/math.in.h (setpayload): New declaration.
* lib/setpayload.c: New file.
* m4/setpayload.m4: New file.
* m4/math_h.m4 (gl_MATH_H): Test whether setpayload is declared.
(gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOAD.
(gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOAD.
* modules/math (Makefile.am): Substitute GNULIB_SETPAYLOAD,
HAVE_SETPAYLOAD.
* modules/setpayload: New file.
* doc/posix-functions/setpayload.texi: Mention the new module.
---
 ChangeLog                           | 14 +++++++
 doc/posix-functions/setpayload.texi |  8 ++--
 lib/math.in.h                       | 16 ++++++++
 lib/setpayload.c                    | 59 +++++++++++++++++++++++++++
 m4/math_h.m4                        |  8 +++-
 m4/setpayload.m4                    | 63 +++++++++++++++++++++++++++++
 modules/math                        |  2 +
 modules/setpayload                  | 36 +++++++++++++++++
 8 files changed, 200 insertions(+), 6 deletions(-)
 create mode 100644 lib/setpayload.c
 create mode 100644 m4/setpayload.m4
 create mode 100644 modules/setpayload

diff --git a/ChangeLog b/ChangeLog
index 8418f71093..4f80fc03e4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2024-04-16  Bruno Haible  <br...@clisp.org>
+
+	setpayload: New module.
+	* lib/math.in.h (setpayload): New declaration.
+	* lib/setpayload.c: New file.
+	* m4/setpayload.m4: New file.
+	* m4/math_h.m4 (gl_MATH_H): Test whether setpayload is declared.
+	(gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOAD.
+	(gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOAD.
+	* modules/math (Makefile.am): Substitute GNULIB_SETPAYLOAD,
+	HAVE_SETPAYLOAD.
+	* modules/setpayload: New file.
+	* doc/posix-functions/setpayload.texi: Mention the new module.
+
 2024-04-15  Collin Funk  <collin.fu...@gmail.com>
 
 	gnulib-tool.py: Optimize directory creation.
diff --git a/doc/posix-functions/setpayload.texi b/doc/posix-functions/setpayload.texi
index e41a059cfa..26109fbd49 100644
--- a/doc/posix-functions/setpayload.texi
+++ b/doc/posix-functions/setpayload.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: setpayload
 
 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 72a61d7044..3a2fb5cde7 100644
--- a/lib/math.in.h
+++ b/lib/math.in.h
@@ -2774,6 +2774,21 @@ _GL_WARN_REAL_FLOATING_DECL (signbit);
 #endif
 
 
+#if @GNULIB_SETPAYLOAD@
+# if !@HAVE_SETPAYLOAD@
+_GL_FUNCDECL_SYS (setpayload, int, (double *, double));
+# endif
+_GL_CXXALIAS_SYS (setpayload, int, (double *, double));
+_GL_CXXALIASWARN (setpayload);
+#elif defined GNULIB_POSIXCHECK
+# undef setpayload
+# if HAVE_RAW_DECL_SETPAYLOAD
+_GL_WARN_ON_USE (setpayload, "setpayload is unportable - "
+                 "use gnulib module setpayload for portability");
+# endif
+#endif
+
+
 #if @GNULIB_TOTALORDERF@
 # if @REPLACE_TOTALORDERF@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -2849,6 +2864,7 @@ _GL_WARN_ON_USE (totalorderl, "totalorderl is unportable - "
 # endif
 #endif
 
+
 _GL_INLINE_HEADER_END
 
 #endif /* _@GUARD_PREFIX@_MATH_H */
diff --git a/lib/setpayload.c b/lib/setpayload.c
new file mode 100644
index 0000000000..fa5c7ad866
--- /dev/null
+++ b/lib/setpayload.c
@@ -0,0 +1,59 @@
+/* Construct a quiet 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 "signed-nan.h"
+
+int
+setpayload (double *result, double payload)
+{
+#if DBL_MANT_DIG == 53
+  if (
+# if defined __hppa || defined __mips__ || defined __sh__
+      /* A zero payload is not allowed, because that would denote Infinity.
+         Cf. snan.h.  */
+      payload > 0.0
+# else
+      payload >= 0.0
+# endif
+      && payload < 2251799813685248.0 /* (double) (1ULL << (DBL_MANT_DIG - 2)) */
+      && payload == (double) (int64_t) payload)
+    {
+      union { uint64_t i; double f; } x;
+      x.f = positive_NaNd ();
+      x.i = (x.i & ~(((uint64_t) 1 << (DBL_MANT_DIG - 2)) - 1))
+            | (int64_t) payload;
+      *result = x.f;
+      return 0;
+    }
+  else
+    {
+      *result = 0.0;
+      return -1;
+    }
+#else
+# error "Please port gnulib setpayload.c to your platform!"
+#endif
+}
diff --git a/m4/math_h.m4 b/m4/math_h.m4
index e164c137e4..2fa5d9fb28 100644
--- a/m4/math_h.m4
+++ b/m4/math_h.m4
@@ -1,5 +1,5 @@
 # math_h.m4
-# serial 126
+# serial 127
 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,
@@ -50,7 +50,9 @@ AC_DEFUN_ONCE([gl_MATH_H]
      logb logbf logbl
      modf modff modfl powf
      remainder remainderf remainderl
-     rint rintf rintl round roundf roundl sinf sinl sinhf sqrtf sqrtl
+     rint rintf rintl round roundf roundl
+     setpayload
+     sinf sinl sinhf sqrtf sqrtl
      tanf tanl tanhf totalorder totalorderf totalorderl trunc truncf truncl])
 ])
 
@@ -157,6 +159,7 @@ AC_DEFUN([gl_MATH_H_REQUIRE_DEFAULTS]
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ROUND])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ROUNDF])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ROUNDL])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOAD])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SIGNBIT])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SINF])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SINL])
@@ -239,6 +242,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS]
   HAVE_REMAINDERF=1;                AC_SUBST([HAVE_REMAINDERF])
   HAVE_RINT=1;                      AC_SUBST([HAVE_RINT])
   HAVE_RINTL=1;                     AC_SUBST([HAVE_RINTL])
+  HAVE_SETPAYLOAD=1;                AC_SUBST([HAVE_SETPAYLOAD])
   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/setpayload.m4 b/m4/setpayload.m4
new file mode 100644
index 0000000000..5238dd0de5
--- /dev/null
+++ b/m4/setpayload.m4
@@ -0,0 +1,63 @@
+# setpayload.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_SETPAYLOADF],
+[
+  AC_REQUIRE([gl_MATH_H_DEFAULTS])
+  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+
+  gl_MATHFUNC([setpayloadf], [int], [(float *, float)])
+  if test $gl_cv_func_setpayloadf_no_libm != yes \
+     && test $gl_cv_func_setpayloadf_in_libm != yes; then
+    HAVE_SETPAYLOADF=0
+  fi
+  if test $HAVE_SETPAYLOADF = 0; then
+    SETPAYLOADF_LIBM=
+  fi
+  AC_SUBST([SETPAYLOADF_LIBM])
+])
+
+AC_DEFUN_ONCE([gl_FUNC_SETPAYLOAD],
+[
+  AC_REQUIRE([gl_MATH_H_DEFAULTS])
+  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+
+  gl_MATHFUNC([setpayload], [int], [(double *, double)])
+  if test $gl_cv_func_setpayload_no_libm != yes \
+     && test $gl_cv_func_setpayload_in_libm != yes; then
+    HAVE_SETPAYLOAD=0
+  fi
+  if test $HAVE_SETPAYLOAD = 0; then
+    SETPAYLOAD_LIBM=
+  fi
+  AC_SUBST([SETPAYLOAD_LIBM])
+])
+
+AC_DEFUN([gl_FUNC_SETPAYLOADL],
+[
+  AC_REQUIRE([gl_MATH_H_DEFAULTS])
+  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+  AC_REQUIRE([gl_LONG_DOUBLE_VS_DOUBLE])
+
+  gl_MATHFUNC([setpayloadl], [int], [(long double *, long double)])
+  if test $gl_cv_func_setpayloadl_no_libm != yes \
+     && test $gl_cv_func_setpayloadl_in_libm != yes; then
+    HAVE_SETPAYLOADL=0
+  fi
+  if test $HAVE_SETPAYLOADL = 0; then
+    dnl Find libraries needed to link lib/setpayloadl.c.
+    if test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1; then
+      AC_REQUIRE([gl_FUNC_SETPAYLOAD])
+      SETPAYLOADL_LIBM="$SETPAYLOAD_LIBM"
+    else
+      SETPAYLOADL_LIBM=
+    fi
+    dnl Prerequisite of lib/setpayloadl.c.
+    gl_LONG_DOUBLE_EXPONENT_LOCATION
+  fi
+  AC_SUBST([SETPAYLOADL_LIBM])
+])
diff --git a/modules/math b/modules/math
index f816d64cd2..8f61f70ae1 100644
--- a/modules/math
+++ b/modules/math
@@ -120,6 +120,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
 	      -e 's/@''GNULIB_ROUND''@/$(GNULIB_ROUND)/g' \
 	      -e 's/@''GNULIB_ROUNDF''@/$(GNULIB_ROUNDF)/g' \
 	      -e 's/@''GNULIB_ROUNDL''@/$(GNULIB_ROUNDL)/g' \
+	      -e 's/@''GNULIB_SETPAYLOAD''@/$(GNULIB_SETPAYLOAD)/g' \
 	      -e 's/@''GNULIB_SIGNBIT''@/$(GNULIB_SIGNBIT)/g' \
 	      -e 's/@''GNULIB_SINF''@/$(GNULIB_SINF)/g' \
 	      -e 's/@''GNULIB_SINL''@/$(GNULIB_SINL)/g' \
@@ -195,6 +196,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
 	      -e 's|@''HAVE_REMAINDERF''@|$(HAVE_REMAINDERF)|g' \
 	      -e 's|@''HAVE_RINT''@|$(HAVE_RINT)|g' \
 	      -e 's|@''HAVE_RINTL''@|$(HAVE_RINTL)|g' \
+	      -e 's|@''HAVE_SETPAYLOAD''@|$(HAVE_SETPAYLOAD)|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/setpayload b/modules/setpayload
new file mode 100644
index 0000000000..677335a3ae
--- /dev/null
+++ b/modules/setpayload
@@ -0,0 +1,36 @@
+Description:
+setpayload function: construct a quiet NaN with a given payload
+
+Files:
+lib/setpayload.c
+m4/mathfunc.m4
+m4/setpayload.m4
+
+Depends-on:
+math
+extensions
+float           [test $HAVE_SETPAYLOAD = 0]
+stdint          [test $HAVE_SETPAYLOAD = 0]
+signed-nan      [test $HAVE_SETPAYLOAD = 0]
+
+configure.ac:
+gl_FUNC_SETPAYLOAD
+gl_CONDITIONAL([GL_COND_OBJ_SETPAYLOAD], [test $HAVE_SETPAYLOAD = 0])
+gl_MATH_MODULE_INDICATOR([setpayload])
+
+Makefile.am:
+if GL_COND_OBJ_SETPAYLOAD
+lib_SOURCES += setpayload.c
+endif
+
+Include:
+<math.h>
+
+Link:
+$(SETPAYLOAD_LIBM)
+
+License:
+LGPL
+
+Maintainer:
+all
-- 
2.34.1

>From 145a6693a33620bea316865796a7c3c745cb7d2a Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Tue, 16 Apr 2024 14:29:16 +0200
Subject: [PATCH 2/6] setpayload: Add tests.

* tests/test-setpayload.c: New file.
* modules/setpayload-tests: New file.
---
 ChangeLog                |  4 ++
 modules/setpayload-tests | 15 +++++++
 tests/test-setpayload.c  | 86 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 105 insertions(+)
 create mode 100644 modules/setpayload-tests
 create mode 100644 tests/test-setpayload.c

diff --git a/ChangeLog b/ChangeLog
index 4f80fc03e4..97d8a3d64f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2024-04-16  Bruno Haible  <br...@clisp.org>
 
+	setpayload: Add tests.
+	* tests/test-setpayload.c: New file.
+	* modules/setpayload-tests: New file.
+
 	setpayload: New module.
 	* lib/math.in.h (setpayload): New declaration.
 	* lib/setpayload.c: New file.
diff --git a/modules/setpayload-tests b/modules/setpayload-tests
new file mode 100644
index 0000000000..068e4caf20
--- /dev/null
+++ b/modules/setpayload-tests
@@ -0,0 +1,15 @@
+Files:
+tests/test-setpayload.c
+tests/infinity.h
+tests/signature.h
+tests/macros.h
+
+Depends-on:
+isnand-nolibm
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-setpayload
+check_PROGRAMS += test-setpayload
+test_setpayload_LDADD = $(LDADD) @SETPAYLOAD_LIBM@
diff --git a/tests/test-setpayload.c b/tests/test-setpayload.c
new file mode 100644
index 0000000000..d539b75ffc
--- /dev/null
+++ b/tests/test-setpayload.c
@@ -0,0 +1,86 @@
+/* Test setpayload.
+   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 (setpayload, int, (double *, double));
+
+#include "infinity.h"
+#include "isnand-nolibm.h"
+#include "macros.h"
+
+int
+main ()
+{
+  int i;
+  double p;
+
+  {
+    /* Test valid payloads.  */
+    for (i = 0, p = 1.0; i < 53 - 2; i++, p *= 2.0)
+      {
+        int ret;
+        double x;
+
+        ret = setpayload (&x, p);
+        ASSERT (ret == 0);
+        ASSERT (isnand (x));
+      }
+    /* Test out-of-range payload.  */
+    int ret;
+    double x;
+
+    ret = setpayload (&x, p);
+    ASSERT (ret != 0);
+    ASSERT (x == 0.0);
+  }
+
+  /* Test infinite payload.  */
+  {
+    int ret;
+    double x;
+
+    ret = setpayload (&x, Infinityd ());
+    ASSERT (ret != 0);
+    ASSERT (x == 0.0);
+  }
+
+  /* Test negative payload.  */
+  {
+    int ret;
+    double x;
+
+    ret = setpayload (&x, -1.0);
+    ASSERT (ret != 0);
+    ASSERT (x == 0.0);
+  }
+
+  /* Test fractional payload.  */
+  {
+    int ret;
+    double x;
+
+    ret = setpayload (&x, 1.4);
+    ASSERT (ret != 0);
+    ASSERT (x == 0.0);
+  }
+
+  return 0;
+}
-- 
2.34.1

>From eaa0ca659f7548c3e7f38231bc4ee7c34770d8f9 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Tue, 16 Apr 2024 14:39:16 +0200
Subject: [PATCH 3/6] setpayloadf: New module.

* lib/math.in.h (setpayloadf): New declaration.
* lib/setpayloadf.c: New file.
* m4/math_h.m4 (gl_MATH_H): Test whether setpayloadf is declared.
(gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOADF.
(gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOADF.
* modules/math (Makefile.am): Substitute GNULIB_SETPAYLOADF,
HAVE_SETPAYLOADF.
* modules/setpayloadf: New file.
* doc/posix-functions/setpayloadf.texi: Mention the new module.
---
 ChangeLog                            | 13 ++++++
 doc/posix-functions/setpayloadf.texi |  8 ++--
 lib/math.in.h                        | 14 +++++++
 lib/setpayloadf.c                    | 59 ++++++++++++++++++++++++++++
 m4/math_h.m4                         |  6 ++-
 modules/math                         |  2 +
 modules/setpayloadf                  | 36 +++++++++++++++++
 7 files changed, 132 insertions(+), 6 deletions(-)
 create mode 100644 lib/setpayloadf.c
 create mode 100644 modules/setpayloadf

diff --git a/ChangeLog b/ChangeLog
index 97d8a3d64f..9640eb8ef1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2024-04-16  Bruno Haible  <br...@clisp.org>
+
+	setpayloadf: New module.
+	* lib/math.in.h (setpayloadf): New declaration.
+	* lib/setpayloadf.c: New file.
+	* m4/math_h.m4 (gl_MATH_H): Test whether setpayloadf is declared.
+	(gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOADF.
+	(gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOADF.
+	* modules/math (Makefile.am): Substitute GNULIB_SETPAYLOADF,
+	HAVE_SETPAYLOADF.
+	* modules/setpayloadf: New file.
+	* doc/posix-functions/setpayloadf.texi: Mention the new module.
+
 2024-04-16  Bruno Haible  <br...@clisp.org>
 
 	setpayload: Add tests.
diff --git a/doc/posix-functions/setpayloadf.texi b/doc/posix-functions/setpayloadf.texi
index c225c1b1f4..05616f9d41 100644
--- a/doc/posix-functions/setpayloadf.texi
+++ b/doc/posix-functions/setpayloadf.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: setpayloadf
 
 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 3a2fb5cde7..1fd41c2722 100644
--- a/lib/math.in.h
+++ b/lib/math.in.h
@@ -2774,6 +2774,20 @@ _GL_WARN_REAL_FLOATING_DECL (signbit);
 #endif
 
 
+#if @GNULIB_SETPAYLOADF@
+# if !@HAVE_SETPAYLOADF@
+_GL_FUNCDECL_SYS (setpayloadf, int, (float *, float));
+# endif
+_GL_CXXALIAS_SYS (setpayloadf, int, (float *, float));
+_GL_CXXALIASWARN (setpayloadf);
+#elif defined GNULIB_POSIXCHECK
+# undef setpayloadf
+# if HAVE_RAW_DECL_SETPAYLOADF
+_GL_WARN_ON_USE (setpayloadf, "setpayloadf is unportable - "
+                 "use gnulib module setpayloadf for portability");
+# endif
+#endif
+
 #if @GNULIB_SETPAYLOAD@
 # if !@HAVE_SETPAYLOAD@
 _GL_FUNCDECL_SYS (setpayload, int, (double *, double));
diff --git a/lib/setpayloadf.c b/lib/setpayloadf.c
new file mode 100644
index 0000000000..1f02bc4593
--- /dev/null
+++ b/lib/setpayloadf.c
@@ -0,0 +1,59 @@
+/* Construct a quiet 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 "signed-nan.h"
+
+int
+setpayloadf (float *result, float payload)
+{
+#if FLT_MANT_DIG == 24
+  if (
+# if defined __hppa || defined __mips__ || defined __sh__
+      /* A zero payload is not allowed, because that would denote Infinity.
+         Cf. snan.h.  */
+      payload > 0.0f
+# else
+      payload >= 0.0f
+# endif
+      && payload < 4194304.0f /* (float) (1U << (FLT_MANT_DIG - 2)) */
+      && payload == (float) (int32_t) payload)
+    {
+      union { uint32_t i; float f; } x;
+      x.f = positive_NaNf ();
+      x.i = (x.i & ~(((uint32_t) 1 << (FLT_MANT_DIG - 2)) - 1))
+            | (int32_t) payload;
+      *result = x.f;
+      return 0;
+    }
+  else
+    {
+      *result = 0.0f;
+      return -1;
+    }
+#else
+# error "Please port gnulib setpayloadf.c to your platform!"
+#endif
+}
diff --git a/m4/math_h.m4 b/m4/math_h.m4
index 2fa5d9fb28..ee32128089 100644
--- a/m4/math_h.m4
+++ b/m4/math_h.m4
@@ -1,5 +1,5 @@
 # math_h.m4
-# serial 127
+# serial 128
 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,
@@ -51,7 +51,7 @@ AC_DEFUN_ONCE([gl_MATH_H]
      modf modff modfl powf
      remainder remainderf remainderl
      rint rintf rintl round roundf roundl
-     setpayload
+     setpayload setpayloadf
      sinf sinl sinhf sqrtf sqrtl
      tanf tanl tanhf totalorder totalorderf totalorderl trunc truncf truncl])
 ])
@@ -160,6 +160,7 @@ AC_DEFUN([gl_MATH_H_REQUIRE_DEFAULTS]
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ROUNDF])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ROUNDL])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOAD])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADF])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SIGNBIT])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SINF])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SINL])
@@ -243,6 +244,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS]
   HAVE_RINT=1;                      AC_SUBST([HAVE_RINT])
   HAVE_RINTL=1;                     AC_SUBST([HAVE_RINTL])
   HAVE_SETPAYLOAD=1;                AC_SUBST([HAVE_SETPAYLOAD])
+  HAVE_SETPAYLOADF=1;               AC_SUBST([HAVE_SETPAYLOADF])
   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 8f61f70ae1..f0233b94c4 100644
--- a/modules/math
+++ b/modules/math
@@ -121,6 +121,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
 	      -e 's/@''GNULIB_ROUNDF''@/$(GNULIB_ROUNDF)/g' \
 	      -e 's/@''GNULIB_ROUNDL''@/$(GNULIB_ROUNDL)/g' \
 	      -e 's/@''GNULIB_SETPAYLOAD''@/$(GNULIB_SETPAYLOAD)/g' \
+	      -e 's/@''GNULIB_SETPAYLOADF''@/$(GNULIB_SETPAYLOADF)/g' \
 	      -e 's/@''GNULIB_SIGNBIT''@/$(GNULIB_SIGNBIT)/g' \
 	      -e 's/@''GNULIB_SINF''@/$(GNULIB_SINF)/g' \
 	      -e 's/@''GNULIB_SINL''@/$(GNULIB_SINL)/g' \
@@ -197,6 +198,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
 	      -e 's|@''HAVE_RINT''@|$(HAVE_RINT)|g' \
 	      -e 's|@''HAVE_RINTL''@|$(HAVE_RINTL)|g' \
 	      -e 's|@''HAVE_SETPAYLOAD''@|$(HAVE_SETPAYLOAD)|g' \
+	      -e 's|@''HAVE_SETPAYLOADF''@|$(HAVE_SETPAYLOADF)|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/setpayloadf b/modules/setpayloadf
new file mode 100644
index 0000000000..05856e62da
--- /dev/null
+++ b/modules/setpayloadf
@@ -0,0 +1,36 @@
+Description:
+setpayloadf function: construct a quiet NaN with a given payload
+
+Files:
+lib/setpayloadf.c
+m4/mathfunc.m4
+m4/setpayload.m4
+
+Depends-on:
+math
+extensions
+float           [test $HAVE_SETPAYLOADF = 0]
+stdint          [test $HAVE_SETPAYLOADF = 0]
+signed-nan      [test $HAVE_SETPAYLOADF = 0]
+
+configure.ac:
+gl_FUNC_SETPAYLOADF
+gl_CONDITIONAL([GL_COND_OBJ_SETPAYLOADF], [test $HAVE_SETPAYLOADF = 0])
+gl_MATH_MODULE_INDICATOR([setpayloadf])
+
+Makefile.am:
+if GL_COND_OBJ_SETPAYLOADF
+lib_SOURCES += setpayloadf.c
+endif
+
+Include:
+<math.h>
+
+Link:
+$(SETPAYLOADF_LIBM)
+
+License:
+LGPL
+
+Maintainer:
+all
-- 
2.34.1

>From 86400484d7e4af4b42df08e8999cfdae77d90d69 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Tue, 16 Apr 2024 14:40:37 +0200
Subject: [PATCH 4/6] setpayloadf: Add tests.

* tests/test-setpayloadf.c: New file.
* modules/setpayloadf-tests: New file.
---
 ChangeLog                 |  4 ++
 modules/setpayloadf-tests | 15 +++++++
 tests/test-setpayloadf.c  | 86 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 105 insertions(+)
 create mode 100644 modules/setpayloadf-tests
 create mode 100644 tests/test-setpayloadf.c

diff --git a/ChangeLog b/ChangeLog
index 9640eb8ef1..1a5dbdf669 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2024-04-16  Bruno Haible  <br...@clisp.org>
 
+	setpayloadf: Add tests.
+	* tests/test-setpayloadf.c: New file.
+	* modules/setpayloadf-tests: New file.
+
 	setpayloadf: New module.
 	* lib/math.in.h (setpayloadf): New declaration.
 	* lib/setpayloadf.c: New file.
diff --git a/modules/setpayloadf-tests b/modules/setpayloadf-tests
new file mode 100644
index 0000000000..75cda25d33
--- /dev/null
+++ b/modules/setpayloadf-tests
@@ -0,0 +1,15 @@
+Files:
+tests/test-setpayloadf.c
+tests/infinity.h
+tests/signature.h
+tests/macros.h
+
+Depends-on:
+isnanf-nolibm
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-setpayloadf
+check_PROGRAMS += test-setpayloadf
+test_setpayloadf_LDADD = $(LDADD) @SETPAYLOADF_LIBM@
diff --git a/tests/test-setpayloadf.c b/tests/test-setpayloadf.c
new file mode 100644
index 0000000000..aa790343ae
--- /dev/null
+++ b/tests/test-setpayloadf.c
@@ -0,0 +1,86 @@
+/* Test setpayloadf.
+   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 (setpayloadf, int, (float *, float));
+
+#include "infinity.h"
+#include "isnanf-nolibm.h"
+#include "macros.h"
+
+int
+main ()
+{
+  int i;
+  float p;
+
+  {
+    /* Test valid payloads.  */
+    for (i = 0, p = 1.0f; i < 24 - 2; i++, p *= 2.0f)
+      {
+        int ret;
+        float x;
+
+        ret = setpayloadf (&x, p);
+        ASSERT (ret == 0);
+        ASSERT (isnanf (x));
+      }
+    /* Test out-of-range payload.  */
+    int ret;
+    float x;
+
+    ret = setpayloadf (&x, p);
+    ASSERT (ret != 0);
+    ASSERT (x == 0.0f);
+  }
+
+  /* Test infinite payload.  */
+  {
+    int ret;
+    float x;
+
+    ret = setpayloadf (&x, Infinityf ());
+    ASSERT (ret != 0);
+    ASSERT (x == 0.0f);
+  }
+
+  /* Test negative payload.  */
+  {
+    int ret;
+    float x;
+
+    ret = setpayloadf (&x, -1.0f);
+    ASSERT (ret != 0);
+    ASSERT (x == 0.0f);
+  }
+
+  /* Test fractional payload.  */
+  {
+    int ret;
+    float x;
+
+    ret = setpayloadf (&x, 1.4f);
+    ASSERT (ret != 0);
+    ASSERT (x == 0.0f);
+  }
+
+  return 0;
+}
-- 
2.34.1

>From 9ee372d31814699a189232c7280d43385776d0d4 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Tue, 16 Apr 2024 14:57:25 +0200
Subject: [PATCH 5/6] setpayloadl: New module.

* lib/math.in.h (setpayloadl): New declaration.
* lib/setpayloadl.c: New file.
* m4/math_h.m4 (gl_MATH_H): Test whether setpayloadl is declared.
(gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOADL.
(gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOADL.
* modules/math (Makefile.am): Substitute GNULIB_SETPAYLOADL,
HAVE_SETPAYLOADL.
* modules/setpayloadl: New file.
* doc/posix-functions/setpayloadl.texi: Mention the new module.
---
 ChangeLog                            |  13 +++
 doc/posix-functions/setpayloadl.texi |   8 +-
 lib/math.in.h                        |  14 +++
 lib/setpayloadl.c                    | 132 +++++++++++++++++++++++++++
 m4/math_h.m4                         |   6 +-
 modules/math                         |   2 +
 modules/setpayloadl                  |  39 ++++++++
 7 files changed, 208 insertions(+), 6 deletions(-)
 create mode 100644 lib/setpayloadl.c
 create mode 100644 modules/setpayloadl

diff --git a/ChangeLog b/ChangeLog
index 1a5dbdf669..baa0043a46 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2024-04-16  Bruno Haible  <br...@clisp.org>
+
+	setpayloadl: New module.
+	* lib/math.in.h (setpayloadl): New declaration.
+	* lib/setpayloadl.c: New file.
+	* m4/math_h.m4 (gl_MATH_H): Test whether setpayloadl is declared.
+	(gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_SETPAYLOADL.
+	(gl_MATH_H_DEFAULTS): Initialize HAVE_SETPAYLOADL.
+	* modules/math (Makefile.am): Substitute GNULIB_SETPAYLOADL,
+	HAVE_SETPAYLOADL.
+	* modules/setpayloadl: New file.
+	* doc/posix-functions/setpayloadl.texi: Mention the new module.
+
 2024-04-16  Bruno Haible  <br...@clisp.org>
 
 	setpayloadf: Add tests.
diff --git a/doc/posix-functions/setpayloadl.texi b/doc/posix-functions/setpayloadl.texi
index 0575529c86..d8bed4b4ae 100644
--- a/doc/posix-functions/setpayloadl.texi
+++ b/doc/posix-functions/setpayloadl.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: setpayloadl
 
 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 1fd41c2722..98da404780 100644
--- a/lib/math.in.h
+++ b/lib/math.in.h
@@ -2802,6 +2802,20 @@ _GL_WARN_ON_USE (setpayload, "setpayload is unportable - "
 # endif
 #endif
 
+#if @GNULIB_SETPAYLOADL@
+# if !@HAVE_SETPAYLOADL@
+_GL_FUNCDECL_SYS (setpayloadl, int, (long double *, long double));
+# endif
+_GL_CXXALIAS_SYS (setpayloadl, int, (long double *, long double));
+_GL_CXXALIASWARN (setpayloadl);
+#elif defined GNULIB_POSIXCHECK
+# undef setpayloadl
+# if HAVE_RAW_DECL_SETPAYLOADL
+_GL_WARN_ON_USE (setpayloadl, "setpayloadl is unportable - "
+                 "use gnulib module setpayloadl for portability");
+# endif
+#endif
+
 
 #if @GNULIB_TOTALORDERF@
 # if @REPLACE_TOTALORDERF@
diff --git a/lib/setpayloadl.c b/lib/setpayloadl.c
new file mode 100644
index 0000000000..7d25bafae0
--- /dev/null
+++ b/lib/setpayloadl.c
@@ -0,0 +1,132 @@
+/* Construct a quiet 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
+setpayloadl (long double *result, long double payload)
+{
+  return setpayload ((double *) result, payload);
+}
+
+#else
+
+# include <float.h>
+# include <stdint.h>
+
+# include "signed-nan.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)))
+
+int
+setpayloadl (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__
+      /* A zero payload is not allowed, because that would denote Infinity.
+         Cf. snan.h.  */
+      payload > 0.0L
+#  else
+      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;
+      x.value = positive_NaNl ();
+
+#  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[0] = (x.word[0] & 0xFFFFC000U) | (uint32_t) (pl >> 48)
+      x.word[1] = (uint32_t) (pl >> 16);
+      x.word[2] = (uint32_t) (pl << 16);
+#   else
+#    error "Please port gnulib setpayloadl.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 setpayloadl.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] & 0xFFFFC000U)
+                                  | (pl.word[LDBL_EXPBIT0_WORD] & 0x00003FFFU);
+      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 setpayloadl.c to your platform!"
+#   endif
+#  endif
+
+      *result = x.value;
+      return 0;
+    }
+  else
+    {
+      *result = 0.0L;
+      return -1;
+    }
+# else
+#  error "Please port gnulib setpayloadl.c to your platform!"
+# endif
+}
+
+#endif
diff --git a/m4/math_h.m4 b/m4/math_h.m4
index ee32128089..3dc779160c 100644
--- a/m4/math_h.m4
+++ b/m4/math_h.m4
@@ -1,5 +1,5 @@
 # math_h.m4
-# serial 128
+# serial 129
 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,
@@ -51,7 +51,7 @@ AC_DEFUN_ONCE([gl_MATH_H]
      modf modff modfl powf
      remainder remainderf remainderl
      rint rintf rintl round roundf roundl
-     setpayload setpayloadf
+     setpayload setpayloadf setpayloadl
      sinf sinl sinhf sqrtf sqrtl
      tanf tanl tanhf totalorder totalorderf totalorderl trunc truncf truncl])
 ])
@@ -161,6 +161,7 @@ AC_DEFUN([gl_MATH_H_REQUIRE_DEFAULTS]
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ROUNDL])
     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_SIGNBIT])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SINF])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SINL])
@@ -245,6 +246,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS]
   HAVE_RINTL=1;                     AC_SUBST([HAVE_RINTL])
   HAVE_SETPAYLOAD=1;                AC_SUBST([HAVE_SETPAYLOAD])
   HAVE_SETPAYLOADF=1;               AC_SUBST([HAVE_SETPAYLOADF])
+  HAVE_SETPAYLOADL=1;               AC_SUBST([HAVE_SETPAYLOADL])
   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 f0233b94c4..80de39a7f7 100644
--- a/modules/math
+++ b/modules/math
@@ -122,6 +122,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
 	      -e 's/@''GNULIB_ROUNDL''@/$(GNULIB_ROUNDL)/g' \
 	      -e 's/@''GNULIB_SETPAYLOAD''@/$(GNULIB_SETPAYLOAD)/g' \
 	      -e 's/@''GNULIB_SETPAYLOADF''@/$(GNULIB_SETPAYLOADF)/g' \
+	      -e 's/@''GNULIB_SETPAYLOADL''@/$(GNULIB_SETPAYLOADL)/g' \
 	      -e 's/@''GNULIB_SIGNBIT''@/$(GNULIB_SIGNBIT)/g' \
 	      -e 's/@''GNULIB_SINF''@/$(GNULIB_SINF)/g' \
 	      -e 's/@''GNULIB_SINL''@/$(GNULIB_SINL)/g' \
@@ -199,6 +200,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
 	      -e 's|@''HAVE_RINTL''@|$(HAVE_RINTL)|g' \
 	      -e 's|@''HAVE_SETPAYLOAD''@|$(HAVE_SETPAYLOAD)|g' \
 	      -e 's|@''HAVE_SETPAYLOADF''@|$(HAVE_SETPAYLOADF)|g' \
+	      -e 's|@''HAVE_SETPAYLOADL''@|$(HAVE_SETPAYLOADL)|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/setpayloadl b/modules/setpayloadl
new file mode 100644
index 0000000000..0a94431d5d
--- /dev/null
+++ b/modules/setpayloadl
@@ -0,0 +1,39 @@
+Description:
+setpayloadl function: construct a quiet NaN with a given payload
+
+Files:
+lib/setpayloadl.c
+m4/mathfunc.m4
+m4/setpayload.m4
+m4/exponentl.m4
+
+Depends-on:
+math
+extensions
+setpayload      [test $HAVE_SETPAYLOADL = 0 && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1]
+float           [test $HAVE_SETPAYLOADL = 0 && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
+stdint          [test $HAVE_SETPAYLOADL = 0 && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
+signed-nan      [test $HAVE_SETPAYLOADL = 0 && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
+snan            [test $HAVE_SETPAYLOADL = 0 && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
+
+configure.ac:
+gl_FUNC_SETPAYLOADL
+gl_CONDITIONAL([GL_COND_OBJ_SETPAYLOADL], [test $HAVE_SETPAYLOADL = 0])
+gl_MATH_MODULE_INDICATOR([setpayloadl])
+
+Makefile.am:
+if GL_COND_OBJ_SETPAYLOADL
+lib_SOURCES += setpayloadl.c
+endif
+
+Include:
+<math.h>
+
+Link:
+$(SETPAYLOADL_LIBM)
+
+License:
+LGPL
+
+Maintainer:
+all
-- 
2.34.1

>From 7996def3f3aace53c526435fecf37a7bd141e043 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Tue, 16 Apr 2024 14:58:57 +0200
Subject: [PATCH 6/6] setpayloadl: Add tests.

* tests/test-setpayloadl.c: New file.
* modules/setpayloadl-tests: New file.
---
 ChangeLog                 |  4 ++
 modules/setpayloadl-tests | 15 ++++++
 tests/test-setpayloadl.c  | 97 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 116 insertions(+)
 create mode 100644 modules/setpayloadl-tests
 create mode 100644 tests/test-setpayloadl.c

diff --git a/ChangeLog b/ChangeLog
index baa0043a46..b14171a863 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2024-04-16  Bruno Haible  <br...@clisp.org>
 
+	setpayloadl: Add tests.
+	* tests/test-setpayloadl.c: New file.
+	* modules/setpayloadl-tests: New file.
+
 	setpayloadl: New module.
 	* lib/math.in.h (setpayloadl): New declaration.
 	* lib/setpayloadl.c: New file.
diff --git a/modules/setpayloadl-tests b/modules/setpayloadl-tests
new file mode 100644
index 0000000000..3b05d04a53
--- /dev/null
+++ b/modules/setpayloadl-tests
@@ -0,0 +1,15 @@
+Files:
+tests/test-setpayloadl.c
+tests/infinity.h
+tests/signature.h
+tests/macros.h
+
+Depends-on:
+isnanl-nolibm
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-setpayloadl
+check_PROGRAMS += test-setpayloadl
+test_setpayloadl_LDADD = $(LDADD) @SETPAYLOADL_LIBM@
diff --git a/tests/test-setpayloadl.c b/tests/test-setpayloadl.c
new file mode 100644
index 0000000000..86139a5247
--- /dev/null
+++ b/tests/test-setpayloadl.c
@@ -0,0 +1,97 @@
+/* Test setpayloadl.
+   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 (setpayloadl, 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 = setpayloadl (&x, p);
+        ASSERT (ret == 0);
+        ASSERT (isnanl (x));
+      }
+    /* Test out-of-range payload.  */
+    int ret;
+    long double x;
+
+    ret = setpayloadl (&x, p);
+    ASSERT (ret != 0);
+    ASSERT (x == 0.0L);
+  }
+
+  /* Test infinite payload.  */
+  {
+    int ret;
+    long double x;
+
+    ret = setpayloadl (&x, Infinityl ());
+    ASSERT (ret != 0);
+    ASSERT (x == 0.0L);
+  }
+
+  /* Test negative payload.  */
+  {
+    int ret;
+    long double x;
+
+    ret = setpayloadl (&x, -1.0L);
+    ASSERT (ret != 0);
+    ASSERT (x == 0.0L);
+  }
+
+  /* Test fractional payload.  */
+  {
+    int ret;
+    long double x;
+
+    ret = setpayloadl (&x, 1.4L);
+    ASSERT (ret != 0);
+    ASSERT (x == 0.0L);
+  }
+
+  return 0;
+}
-- 
2.34.1

Reply via email to