bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

log2l: Work around musl libc bug


From: Bruno Haible
Subject: log2l: Work around musl libc bug
Date: Sun, 31 Jan 2021 13:20:55 +0100
User-agent: KMail/5.1.3 (Linux/4.4.0-197-generic; KDE/5.18.0; x86_64; ; )

log2l lacks precision on musl libc 1.2.2/arm64, musl libc 1.2.2/s390x.
This patch adds a configure test, that enables a gnulib workaround.


2021-01-31  Bruno Haible  <bruno@clisp.org>

        log2l: Work around musl libc bugs.
        * doc/posix-functions/log2l.texi: Document musl libc bugs.
        * m4/log2l.m4 (gl_FUNC_LOG2L_WORKS): Add more tests. Update cross
        compilation guess.

diff --git a/doc/posix-functions/log2l.texi b/doc/posix-functions/log2l.texi
index 24e367c..563a67e 100644
--- a/doc/posix-functions/log2l.texi
+++ b/doc/posix-functions/log2l.texi
@@ -14,6 +14,13 @@ FreeBSD 6.0, NetBSD 9.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, 
HP-UX 11, older IRIX
 @item
 This function is not declared on some platforms:
 IRIX 6.5.
+@item
+This function produces results which are accurate to only 16 digits on some
+platforms:
+musl libc 1.2.2/arm64, musl libc 1.2.2/s390x.
+@item
+This function returns Infinity for some large finite arguments on some 
platforms:
+musl libc 1.2.2/arm64, musl libc 1.2.2/s390x.
 @end itemize
 
 Portability problems not fixed by Gnulib:
diff --git a/m4/log2l.m4 b/m4/log2l.m4
index 4776543..cd8e984 100644
--- a/m4/log2l.m4
+++ b/m4/log2l.m4
@@ -1,4 +1,4 @@
-# log2l.m4 serial 2
+# log2l.m4 serial 3
 dnl Copyright (C) 2010-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -69,6 +69,7 @@ AC_DEFUN([gl_FUNC_LOG2L],
 
 dnl Test whether log2l() works.
 dnl On OSF/1 5.1, log2l(-0.0) is NaN.
+dnl On musl 1.2.2/{arm64,s390x}, the result is accurate to only 16 digits.
 AC_DEFUN([gl_FUNC_LOG2L_WORKS],
 [
   AC_REQUIRE([AC_PROG_CC])
@@ -77,7 +78,40 @@ AC_DEFUN([gl_FUNC_LOG2L_WORKS],
     [
       AC_RUN_IFELSE(
         [AC_LANG_SOURCE([[
+#ifndef __NO_MATH_INLINES
+# define __NO_MATH_INLINES 1 /* for glibc */
+#endif
+#include <float.h>
 #include <math.h>
+/* Override the values of <float.h>, like done in float.in.h.  */
+#if defined __i386__ && (defined __BEOS__ || defined __OpenBSD__)
+# undef LDBL_MANT_DIG
+# define LDBL_MANT_DIG   64
+# undef LDBL_MIN_EXP
+# define LDBL_MIN_EXP    (-16381)
+# undef LDBL_MAX_EXP
+# define LDBL_MAX_EXP    16384
+#endif
+#if defined __i386__ && (defined __FreeBSD__ || defined __DragonFly__)
+# undef LDBL_MANT_DIG
+# define LDBL_MANT_DIG   64
+# undef LDBL_MIN_EXP
+# define LDBL_MIN_EXP    (-16381)
+# undef LDBL_MAX_EXP
+# define LDBL_MAX_EXP    16384
+#endif
+#if (defined _ARCH_PPC || defined _POWER) && defined _AIX && (LDBL_MANT_DIG == 
106) && defined __GNUC__
+# undef LDBL_MIN_EXP
+# define LDBL_MIN_EXP DBL_MIN_EXP
+#endif
+#if defined __sgi && (LDBL_MANT_DIG >= 106)
+# undef LDBL_MANT_DIG
+# define LDBL_MANT_DIG 106
+# if defined __GNUC__
+#  undef LDBL_MIN_EXP
+#  define LDBL_MIN_EXP DBL_MIN_EXP
+# endif
+#endif
 #ifndef log2l /* for AIX */
 extern
 #ifdef __cplusplus
@@ -85,25 +119,59 @@ extern
 #endif
 long double log2l (long double);
 #endif
-volatile long double x;
-volatile long double y;
-int main ()
+static long double dummy (long double x) { return 0; }
+volatile long double gx;
+volatile long double gy;
+int main (int argc, char *argv[])
 {
+  long double (* volatile my_log2l) (long double) = argc ? log2l : dummy;
+  int result = 0;
   /* This test fails on OSF/1 5.1.  */
-  x = -0.0L;
-  y = log2l (x);
-  if (!(y + y == y))
-    return 1;
-  return 0;
+  {
+    gx = -0.0L;
+    gy = my_log2l (gx);
+    if (!(gy + gy == gy))
+      result |= 1;
+  }
+  /* This test fails on musl 1.2.2/arm64, musl 1.2.2/s390x.  */
+  {
+    const long double TWO_LDBL_MANT_DIG = /* 2^LDBL_MANT_DIG */
+      (long double) (1U << ((LDBL_MANT_DIG - 1) / 5))
+      * (long double) (1U << ((LDBL_MANT_DIG - 1 + 1) / 5))
+      * (long double) (1U << ((LDBL_MANT_DIG - 1 + 2) / 5))
+      * (long double) (1U << ((LDBL_MANT_DIG - 1 + 3) / 5))
+      * (long double) (1U << ((LDBL_MANT_DIG - 1 + 4) / 5));
+    long double x = 11.358L;
+    long double y = my_log2l (x);
+    long double z = my_log2l (1.0L / x);
+    long double err = (y + z) * TWO_LDBL_MANT_DIG;
+    if (!(err >= -10000.0L && err <= 10000.0L))
+      result |= 2;
+  }
+  /* This test fails on musl 1.2.2/arm64, musl 1.2.2/s390x.  */
+  if (DBL_MAX_EXP < LDBL_MAX_EXP)
+    {
+      long double x = ldexpl (1.0L, DBL_MAX_EXP); /* finite! */
+      long double y = my_log2l (x);
+      if (y > 0 && y + y == y) /* infinite? */
+        result |= 4;
+    }
+  return result;
 }
 ]])],
         [gl_cv_func_log2l_works=yes],
         [gl_cv_func_log2l_works=no],
         [case "$host_os" in
-           osf*)   gl_cv_func_log2l_works="guessing no" ;;
-                   # Guess yes on native Windows.
-           mingw*) gl_cv_func_log2l_works="guessing yes" ;;
-           *)      gl_cv_func_log2l_works="guessing yes" ;;
+                          # Guess yes on glibc systems.
+           *-gnu* | gnu*) gl_cv_func_log2l_works="guessing yes" ;;
+                          # Guess no on musl systems.
+           *-musl*)       gl_cv_func_log2l_works="guessing no" ;;
+                          # Guess no on OSF/1.
+           osf*)          gl_cv_func_log2l_works="guessing no" ;;
+                          # Guess yes on native Windows.
+           mingw*)        gl_cv_func_log2l_works="guessing yes" ;;
+                          # If we don't know, obey --enable-cross-guesses.
+           *)             gl_cv_func_log2l_works="$gl_cross_guess_normal" ;;
          esac
         ])
     ])




reply via email to

[Prev in Thread] Current Thread [Next in Thread]