bug-gnulib
[Top][All Lists]
Advanced

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

sqrtl on OpenBSD 5.1/SPARC


From: Bruno Haible
Subject: sqrtl on OpenBSD 5.1/SPARC
Date: Wed, 14 Mar 2012 01:52:26 +0100
User-agent: KMail/4.7.4 (Linux/3.1.0-1.2-desktop; KDE/4.7.4; x86_64; ; )

On OpenBSD 5.1/SPARC64, the sqrtl() function returns values that have a
relative error > 50000000 ulp. Obviously unusable. Witness:

#include <math.h>
#include <stdio.h>
int main ()
{
  volatile long double a = 8.1974099812331540680810141969554806865L;
  volatile long double b = sqrtl (a);
  volatile long double c = b * b;
  printf ("%.36Lg\n%.36Lg\n%.36Lg\n%.36Lg\n", a, b, c, c-a);
  return 0;
}

prints

8.1974099812331540680810141969554800813
2.863111940045861080044397012682076147
8.1974099812331744117149208728836063001
2.0343633906675928126218841258144957861e-14

Here's the workaround:


2012-03-13  Bruno Haible  <address@hidden>

        sqrtl: Bypass broken implementation in OpenBSD 5.1/SPARC.
        * lib/math.in.h (sqrtl): Replace it if REPLACE_SQRTL is 1.
        * m4/sqrtl.m4 (gl_FUNC_SQRTL_WORKS): New macro.
        (gl_FUNC_SQRTL): Invoke it. Set REPLACE_SQRTL to 1 if sqrtl() produces
        too big rounding errors.
        * m4/math_h.m4 (gl_MATH_H_DEFAULTS): Initialize REPLACE_SQRTL.
        * modules/math (Makefile.am): Substitute REPLACE_SQRTL.
        * modules/sqrtl (configure.ac): Consider REPLACE_SQRTL.
        (Depends-on): Update conditions.
        * tests/test-sqrtl.c (my_ldexpl): New function.
        (main): Add test of a particular value.
        * doc/posix-functions/sqrtl.texi: Mention the OpenBSD 5.1/SPARC bug.

--- doc/posix-functions/sqrtl.texi.orig Wed Mar 14 01:45:33 2012
+++ doc/posix-functions/sqrtl.texi      Wed Mar 14 01:13:59 2012
@@ -17,6 +17,9 @@
 @item
 This function is not declared on some platforms:
 MacOS X 10.3.
address@hidden
+This function produces very imprecise results on some platforms:
+OpenBSD 5.1/SPARC.
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- lib/math.in.h.orig  Wed Mar 14 01:45:33 2012
+++ lib/math.in.h       Wed Mar 14 01:12:33 2012
@@ -1698,11 +1698,20 @@
 #endif
 
 #if @GNULIB_SQRTL@
-# if address@hidden@ || address@hidden@
-#  undef sqrtl
+# if @REPLACE_SQRTL@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef sqrtl
+#   define sqrtl rpl_sqrtl
+#  endif
+_GL_FUNCDECL_RPL (sqrtl, long double, (long double x));
+_GL_CXXALIAS_RPL (sqrtl, long double, (long double x));
+# else
+#  if address@hidden@ || address@hidden@
+#   undef sqrtl
 _GL_FUNCDECL_SYS (sqrtl, long double, (long double x));
-# endif
+#  endif
 _GL_CXXALIAS_SYS (sqrtl, long double, (long double x));
+# endif
 _GL_CXXALIASWARN (sqrtl);
 #elif defined GNULIB_POSIXCHECK
 # undef sqrtl
--- m4/math_h.m4.orig   Wed Mar 14 01:45:33 2012
+++ m4/math_h.m4        Wed Mar 14 01:13:01 2012
@@ -1,4 +1,4 @@
-# math_h.m4 serial 103
+# math_h.m4 serial 104
 dnl Copyright (C) 2007-2012 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -295,6 +295,7 @@
   REPLACE_ROUNDL=0;            AC_SUBST([REPLACE_ROUNDL])
   REPLACE_SIGNBIT=0;           AC_SUBST([REPLACE_SIGNBIT])
   REPLACE_SIGNBIT_USING_GCC=0; AC_SUBST([REPLACE_SIGNBIT_USING_GCC])
+  REPLACE_SQRTL=0;             AC_SUBST([REPLACE_SQRTL])
   REPLACE_TRUNC=0;             AC_SUBST([REPLACE_TRUNC])
   REPLACE_TRUNCF=0;            AC_SUBST([REPLACE_TRUNCF])
   REPLACE_TRUNCL=0;            AC_SUBST([REPLACE_TRUNCL])
--- m4/sqrtl.m4.orig    Wed Mar 14 01:45:33 2012
+++ m4/sqrtl.m4 Wed Mar 14 01:34:41 2012
@@ -1,4 +1,4 @@
-# sqrtl.m4 serial 7
+# sqrtl.m4 serial 8
 dnl Copyright (C) 2010-2012 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -58,9 +58,20 @@
     dnl Also check whether it's declared.
     dnl MacOS X 10.3 has sqrtl() in libc but doesn't declare it in <math.h>.
     AC_CHECK_DECL([sqrtl], , [HAVE_DECL_SQRTL=0], [[#include <math.h>]])
+
+    save_LIBS="$LIBS"
+    LIBS="$LIBS $SQRTL_LIBM"
+    gl_FUNC_SQRTL_WORKS
+    LIBS="$save_LIBS"
+    case "$gl_cv_func_sqrtl_works" in
+      *yes) ;;
+      *) REPLACE_SQRTL=1 ;;
+    esac
   else
     HAVE_DECL_SQRTL=0
     HAVE_SQRTL=0
+  fi
+  if test $HAVE_SQRTL = 0 || test $REPLACE_SQRTL = 1; then
     dnl Find libraries needed to link lib/sqrtl.c.
     if test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1; then
       AC_REQUIRE([gl_FUNC_SQRT])
@@ -94,3 +105,56 @@
   fi
   AC_SUBST([SQRTL_LIBM])
 ])
+
+dnl Test whether sqrtl() works.
+dnl On OpenBSD 5.1/SPARC, sqrtl(8.1974099812331540680810141969554806865L) has
+dnl rounding errors that eat up the last 8 to 9 decimal digits.
+AC_DEFUN([gl_FUNC_SQRTL_WORKS],
+[
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+  AC_CACHE_CHECK([whether sqrtl works], [gl_cv_func_sqrtl_works],
+    [
+      AC_RUN_IFELSE(
+        [AC_LANG_SOURCE([[
+#include <float.h>
+#include <math.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+long double sqrtl (long double);
+static long double
+my_ldexpl (long double x, int d)
+{
+  for (; d > 0; d--)
+    x *= 2.0L;
+  for (; d < 0; d++)
+    x *= 0.5L;
+  return x;
+}
+volatile long double x;
+volatile long double y;
+long double z;
+int main ()
+{
+  x = 8.1974099812331540680810141969554806865L;
+  y = sqrtl (x);
+  z = y * y - x;
+  z = my_ldexpl (z, LDBL_MANT_DIG);
+  if (z < 0)
+    z = - z;
+  if (z > 100.0L)
+    return 1;
+  return 0;
+}
+]])],
+        [gl_cv_func_sqrtl_works=yes],
+        [gl_cv_func_sqrtl_works=no],
+        [case "$host_os" in
+           osf*) gl_cv_func_sqrtl_works="guessing no";;
+           *)    gl_cv_func_sqrtl_works="guessing yes";;
+         esac
+        ])
+    ])
+])
--- modules/math.orig   Wed Mar 14 01:45:33 2012
+++ modules/math        Wed Mar 14 01:13:28 2012
@@ -262,6 +262,7 @@
              -e 's|@''REPLACE_ROUNDL''@|$(REPLACE_ROUNDL)|g' \
              -e 's|@''REPLACE_SIGNBIT''@|$(REPLACE_SIGNBIT)|g' \
              -e 
's|@''REPLACE_SIGNBIT_USING_GCC''@|$(REPLACE_SIGNBIT_USING_GCC)|g' \
+             -e 's|@''REPLACE_SQRTL''@|$(REPLACE_SQRTL)|g' \
              -e 's|@''REPLACE_TRUNC''@|$(REPLACE_TRUNC)|g' \
              -e 's|@''REPLACE_TRUNCF''@|$(REPLACE_TRUNCF)|g' \
              -e 's|@''REPLACE_TRUNCL''@|$(REPLACE_TRUNCL)|g' \
--- modules/sqrtl.orig  Wed Mar 14 01:45:33 2012
+++ modules/sqrtl       Wed Mar 14 01:15:15 2012
@@ -8,15 +8,15 @@
 Depends-on:
 math
 extensions
-sqrt            [test $HAVE_SQRTL = 0]
-float           [test $HAVE_SQRTL = 0 && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE 
= 0]
-isnanl          [test $HAVE_SQRTL = 0 && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE 
= 0]
-frexpl          [test $HAVE_SQRTL = 0 && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE 
= 0]
-ldexpl          [test $HAVE_SQRTL = 0 && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE 
= 0]
+sqrt            [{ test $HAVE_SQRTL = 0 || test $REPLACE_SQRTL = 1; }]
+float           [{ test $HAVE_SQRTL = 0 || test $REPLACE_SQRTL = 1; } && test 
$HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
+isnanl          [{ test $HAVE_SQRTL = 0 || test $REPLACE_SQRTL = 1; } && test 
$HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
+frexpl          [{ test $HAVE_SQRTL = 0 || test $REPLACE_SQRTL = 1; } && test 
$HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
+ldexpl          [{ test $HAVE_SQRTL = 0 || test $REPLACE_SQRTL = 1; } && test 
$HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
 
 configure.ac:
 gl_FUNC_SQRTL
-if test $HAVE_SQRTL = 0; then
+if test $HAVE_SQRTL = 0 || test $REPLACE_SQRTL = 1; then
   AC_LIBOBJ([sqrtl])
 fi
 gl_MATH_MODULE_INDICATOR([sqrtl])
--- tests/test-sqrtl.c.orig     Wed Mar 14 01:45:33 2012
+++ tests/test-sqrtl.c  Wed Mar 14 01:32:13 2012
@@ -35,6 +35,16 @@
 #define RANDOM randoml
 #include "test-sqrt.h"
 
+static long double
+my_ldexpl (long double x, int d)
+{
+  for (; d > 0; d--)
+    x *= 2.0L;
+  for (; d < 0; d++)
+    x *= 0.5L;
+  return x;
+}
+
 int
 main ()
 {
@@ -47,6 +57,20 @@
   y = sqrtl (x);
   ASSERT (y >= 0.7745966692L && y <= 0.7745966693L);
 
+  /* Another particular value.  */
+  {
+    long double z;
+    long double err;
+
+    x = 8.1974099812331540680810141969554806865L;
+    y = sqrtl (x);
+    z = y * y - x;
+    err = my_ldexpl (z, LDBL_MANT_DIG);
+    if (err < 0)
+      err = - err;
+    ASSERT (err <= 100.0L);
+  }
+
   test_function ();
 
   return 0;




reply via email to

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