>From 63f3bcdc9a42de17310dc636e031385a0feeaeff Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 17 Apr 2024 11:08:40 +0200 Subject: [PATCH 5/6] getpayloadl: New module. * lib/math.in.h (getpayloadl): New declaration. * lib/getpayloadl.c: New file. * m4/math_h.m4 (gl_MATH_H): Test whether getpayloadl is declared. (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_GETPAYLOADL. (gl_MATH_H_DEFAULTS): Initialize HAVE_GETPAYLOADL, REPLACE_GETPAYLOADL. * modules/math (Makefile.am): Substitute GNULIB_GETPAYLOADL, HAVE_GETPAYLOADL, REPLACE_GETPAYLOADL. * modules/getpayloadl: New file. * doc/posix-functions/getpayloadl.texi: Mention the new module and the glibc bug. --- ChangeLog | 14 ++++ doc/posix-functions/getpayloadl.texi | 12 ++-- lib/getpayloadl.c | 100 +++++++++++++++++++++++++++ lib/math.in.h | 23 ++++++ m4/math_h.m4 | 7 +- modules/getpayloadl | 40 +++++++++++ modules/math | 3 + 7 files changed, 193 insertions(+), 6 deletions(-) create mode 100644 lib/getpayloadl.c create mode 100644 modules/getpayloadl diff --git a/ChangeLog b/ChangeLog index 863442a263..bcc40cb255 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2024-04-17 Bruno Haible + + getpayloadl: New module. + * lib/math.in.h (getpayloadl): New declaration. + * lib/getpayloadl.c: New file. + * m4/math_h.m4 (gl_MATH_H): Test whether getpayloadl is declared. + (gl_MATH_H_REQUIRE_DEFAULTS): Initialize GNULIB_GETPAYLOADL. + (gl_MATH_H_DEFAULTS): Initialize HAVE_GETPAYLOADL, REPLACE_GETPAYLOADL. + * modules/math (Makefile.am): Substitute GNULIB_GETPAYLOADL, + HAVE_GETPAYLOADL, REPLACE_GETPAYLOADL. + * modules/getpayloadl: New file. + * doc/posix-functions/getpayloadl.texi: Mention the new module and the + glibc bug. + 2024-04-17 Bruno Haible getpayloadf: Add tests. diff --git a/doc/posix-functions/getpayloadl.texi b/doc/posix-functions/getpayloadl.texi index b3f6471a67..8b1273b367 100644 --- a/doc/posix-functions/getpayloadl.texi +++ b/doc/posix-functions/getpayloadl.texi @@ -10,15 +10,19 @@ @url{https://www.gnu.org/software/libc/manual/html_node/FP-Bit-Twiddling.html}. @end ifnotinfo -Gnulib module: --- +Gnulib module: getpayloadl Portability problems fixed by Gnulib: @itemize +@item +This function is missing on all non-glibc platforms: +glibc 2.24, macOS 11.1, FreeBSD 14.0, NetBSD 10.0, OpenBSD 6.7, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, Solaris 11.4, Cygwin 2.9, mingw, MSVC 14, Android 9.0. +@item +This function returns a wrong result for non-NaN arguments on some platforms: +@c https://sourceware.org/bugzilla/show_bug.cgi?id=26073 +glibc 2.31. @end itemize Portability problems not fixed by Gnulib: @itemize -@item -This function is missing on all non-glibc platforms: -glibc 2.24, macOS 11.1, FreeBSD 14.0, NetBSD 10.0, OpenBSD 6.7, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, Solaris 11.4, Cygwin 2.9, mingw, MSVC 14, Android 9.0. @end itemize diff --git a/lib/getpayloadl.c b/lib/getpayloadl.c new file mode 100644 index 0000000000..6eefb56182 --- /dev/null +++ b/lib/getpayloadl.c @@ -0,0 +1,100 @@ +/* Extract the payload of a NaN 'long double'. + Copyright 2024 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +/* Written by Bruno Haible. */ + +#include + +/* Specification. */ +#include + +#if HAVE_SAME_LONG_DOUBLE_AS_DOUBLE + +long double +getpayloadl (const long double *value) +{ + return getpayload ((const double *) value); +} + +#else + +# include +# include + +# include "snan.h" + +/* 2^(LDBL_MANT_DIG-1). */ +# define TWO_LDBL_MANT_DIG \ + ((long double) (1U << ((LDBL_MANT_DIG - 1) / 4)) \ + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 1) / 4)) \ + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 2) / 4)) \ + * (long double) (1U << ((LDBL_MANT_DIG - 1 + 3) / 4))) + +long double +getpayloadl (const long double *value) +{ + if (isnanl (*value)) + { +# if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 106 || LDBL_MANT_DIG == 113) \ + && defined LDBL_EXPBIT0_WORD && defined LDBL_EXPBIT0_BIT + memory_long_double x; + x.value = *value; +# if LDBL_MANT_DIG == 64 /* on i386, x86_64, ia64, m68k */ + int64_t payload; +# if LDBL_EXPBIT0_WORD == 2 && LDBL_EXPBIT0_BIT == 0 /* on i386, x86_64, ia64 */ + payload = ((uint64_t) (x.word[1] & 0x3FFFFFFFU) << 32) | x.word[0]; +# elif LDBL_EXPBIT0_WORD == 0 && LDBL_EXPBIT0_BIT == 16 /* on m68k */ + payload = ((uint64_t) (x.word[1] & 0x3FFFFFFFU) << 32) | x.word[2]; +# else +# error "Please port gnulib getpayloadl.c to your platform!" +# endif + return payload; +# endif +# if LDBL_MANT_DIG == 106 /* on powerpc, powerpc64, powerpc64le */ + int64_t payload; +# if LDBL_EXPBIT0_BIT == 20 + payload = ((uint64_t) (x.word[LDBL_EXPBIT0_WORD] & 0x0007FFFFU) << 32) + | x.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 1 : -1)]; +# else +# error "Please port gnulib getpayloadl.c to your platform!" +# endif + return payload; +# endif +# if LDBL_MANT_DIG == 113 /* on alpha, arm64, loongarch64, mips64, riscv64, s390x, sparc64 */ +# if LDBL_EXPBIT0_BIT == 16 + memory_long_double pl; + pl.value = TWO_LDBL_MANT_DIG; + pl.word[LDBL_EXPBIT0_WORD] |= x.word[LDBL_EXPBIT0_WORD] & 0x00007FFFU; + pl.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 1 : -1)] = + x.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 1 : -1)]; + pl.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 2 : -2)] = + x.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 2 : -2)]; + pl.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 3 : -3)] = + x.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD == 0 ? 3 : -3)]; + return pl.value - TWO_LDBL_MANT_DIG; +# else +# error "Please port gnulib getpayloadl.c to your platform!" +# endif +# endif +# else +# error "Please port gnulib getpayloadl.c to your platform!" +# endif + } + else + return -1.0L; +} + +#endif diff --git a/lib/math.in.h b/lib/math.in.h index 7a59c8cf35..84b743e7ab 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -2820,6 +2820,29 @@ _GL_WARN_ON_USE (getpayload, "getpayload is unportable - " # endif #endif +#if @GNULIB_GETPAYLOADL@ +# if @REPLACE_GETPAYLOADL@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef getpayloadl +# define getpayloadl rpl_getpayloadl +# endif +_GL_FUNCDECL_RPL (getpayloadl, long double, (const long double *)); +_GL_CXXALIAS_RPL (getpayloadl, long double, (const long double *)); +# else +# if !@HAVE_GETPAYLOADL@ +_GL_FUNCDECL_SYS (getpayloadl, long double, (const long double *)); +# endif +_GL_CXXALIAS_SYS (getpayloadl, long double, (const long double *)); +# endif +_GL_CXXALIASWARN (getpayloadl); +#elif defined GNULIB_POSIXCHECK +# undef getpayloadl +# if HAVE_RAW_DECL_GETPAYLOADL +_GL_WARN_ON_USE (getpayloadl, "getpayloadl is unportable - " + "use gnulib module getpayloadl for portability"); +# endif +#endif + #if @GNULIB_SETPAYLOADF@ # if !@HAVE_SETPAYLOADF@ diff --git a/m4/math_h.m4 b/m4/math_h.m4 index 12aafb7fe9..217c4d225d 100644 --- a/m4/math_h.m4 +++ b/m4/math_h.m4 @@ -1,5 +1,5 @@ # math_h.m4 -# serial 134 +# serial 135 dnl Copyright (C) 2007-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -44,7 +44,7 @@ AC_DEFUN_ONCE([gl_MATH_H] expf expl exp2 exp2f exp2l expm1 expm1f expm1l fabsf fabsl floorf floorl fma fmaf fmal fmod fmodf fmodl frexpf frexpl - getpayload getpayloadf + getpayload getpayloadf getpayloadl hypotf hypotl ilogb ilogbf ilogbl ldexpf ldexpl @@ -121,6 +121,7 @@ AC_DEFUN([gl_MATH_H_REQUIRE_DEFAULTS] gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREXPL]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPAYLOAD]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPAYLOADF]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPAYLOADL]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOT]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOTF]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOTL]) @@ -229,6 +230,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS] HAVE_FREXPF=1; AC_SUBST([HAVE_FREXPF]) HAVE_GETPAYLOAD=1; AC_SUBST([HAVE_GETPAYLOAD]) HAVE_GETPAYLOADF=1; AC_SUBST([HAVE_GETPAYLOADF]) + HAVE_GETPAYLOADL=1; AC_SUBST([HAVE_GETPAYLOADL]) HAVE_HYPOTF=1; AC_SUBST([HAVE_HYPOTF]) HAVE_HYPOTL=1; AC_SUBST([HAVE_HYPOTL]) HAVE_ILOGB=1; AC_SUBST([HAVE_ILOGB]) @@ -340,6 +342,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS] REPLACE_FREXPL=0; AC_SUBST([REPLACE_FREXPL]) REPLACE_GETPAYLOAD=0; AC_SUBST([REPLACE_GETPAYLOAD]) REPLACE_GETPAYLOADF=0; AC_SUBST([REPLACE_GETPAYLOADF]) + REPLACE_GETPAYLOADL=0; AC_SUBST([REPLACE_GETPAYLOADL]) REPLACE_HUGE_VAL=0; AC_SUBST([REPLACE_HUGE_VAL]) REPLACE_HYPOT=0; AC_SUBST([REPLACE_HYPOT]) REPLACE_HYPOTF=0; AC_SUBST([REPLACE_HYPOTF]) diff --git a/modules/getpayloadl b/modules/getpayloadl new file mode 100644 index 0000000000..3ddd0a57ef --- /dev/null +++ b/modules/getpayloadl @@ -0,0 +1,40 @@ +Description: +getpayloadl function: extract the payload of a NaN + +Files: +lib/getpayloadl.c +m4/mathfunc.m4 +m4/getpayload.m4 +m4/exponentl.m4 + +Depends-on: +math +extensions +getpayload [{ test $HAVE_GETPAYLOADL = 0 || test $REPLACE_GETPAYLOADL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1] +float [{ test $HAVE_GETPAYLOADL = 0 || test $REPLACE_GETPAYLOADL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] +stdint [{ test $HAVE_GETPAYLOADL = 0 || test $REPLACE_GETPAYLOADL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] +isnanl [{ test $HAVE_GETPAYLOADL = 0 || test $REPLACE_GETPAYLOADL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] +snan [{ test $HAVE_GETPAYLOADL = 0 || test $REPLACE_GETPAYLOADL = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] + +configure.ac: +gl_FUNC_GETPAYLOADL +gl_CONDITIONAL([GL_COND_OBJ_GETPAYLOADL], + [test $HAVE_GETPAYLOADL = 0 || test $REPLACE_GETPAYLOADL = 1]) +gl_MATH_MODULE_INDICATOR([getpayloadl]) + +Makefile.am: +if GL_COND_OBJ_GETPAYLOADL +lib_SOURCES += getpayloadl.c +endif + +Include: + + +Link: +$(GETPAYLOADL_LIBM) + +License: +LGPL + +Maintainer: +all diff --git a/modules/math b/modules/math index a8c9646124..8c853f0979 100644 --- a/modules/math +++ b/modules/math @@ -77,6 +77,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's/@''GNULIB_FREXPL''@/$(GNULIB_FREXPL)/g' \ -e 's/@''GNULIB_GETPAYLOAD''@/$(GNULIB_GETPAYLOAD)/g' \ -e 's/@''GNULIB_GETPAYLOADF''@/$(GNULIB_GETPAYLOADF)/g' \ + -e 's/@''GNULIB_GETPAYLOADL''@/$(GNULIB_GETPAYLOADL)/g' \ -e 's/@''GNULIB_HYPOT''@/$(GNULIB_HYPOT)/g' \ -e 's/@''GNULIB_HYPOTF''@/$(GNULIB_HYPOTF)/g' \ -e 's/@''GNULIB_HYPOTL''@/$(GNULIB_HYPOTL)/g' \ @@ -180,6 +181,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''HAVE_FREXPF''@|$(HAVE_FREXPF)|g' \ -e 's|@''HAVE_GETPAYLOAD''@|$(HAVE_GETPAYLOAD)|g' \ -e 's|@''HAVE_GETPAYLOADF''@|$(HAVE_GETPAYLOADF)|g' \ + -e 's|@''HAVE_GETPAYLOADL''@|$(HAVE_GETPAYLOADL)|g' \ -e 's|@''HAVE_HYPOTF''@|$(HAVE_HYPOTF)|g' \ -e 's|@''HAVE_HYPOTL''@|$(HAVE_HYPOTL)|g' \ -e 's|@''HAVE_ILOGB''@|$(HAVE_ILOGB)|g' \ @@ -295,6 +297,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''REPLACE_FREXPL''@|$(REPLACE_FREXPL)|g' \ -e 's|@''REPLACE_GETPAYLOAD''@|$(REPLACE_GETPAYLOAD)|g' \ -e 's|@''REPLACE_GETPAYLOADF''@|$(REPLACE_GETPAYLOADF)|g' \ + -e 's|@''REPLACE_GETPAYLOADL''@|$(REPLACE_GETPAYLOADL)|g' \ -e 's|@''REPLACE_HUGE_VAL''@|$(REPLACE_HUGE_VAL)|g' \ -e 's|@''REPLACE_HYPOT''@|$(REPLACE_HYPOT)|g' \ -e 's|@''REPLACE_HYPOTF''@|$(REPLACE_HYPOTF)|g' \ -- 2.34.1