summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog17
-rw-r--r--doc/posix-functions/logb.texi9
-rw-r--r--lib/logb.c71
-rw-r--r--lib/math.in.h37
-rw-r--r--m4/logb.m471
-rw-r--r--m4/math_h.m410
-rw-r--r--modules/logb7
-rw-r--r--modules/math5
-rw-r--r--tests/test-math-c++.cc6
9 files changed, 207 insertions, 26 deletions
diff --git a/ChangeLog b/ChangeLog
index 729e245ccc..b4c162d212 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,22 @@
2012-04-02 Bruno Haible <bruno@clisp.org>
+ logb: Provide replacement and workarounds.
+ * lib/math.in.h (logb): Ensure declaration. Replace if REPLACE_LOGB
+ is 1.
+ * lib/logb.c: New file.
+ * m4/logb.m4 (gl_FUNC_LOGB_WORKS): New macro.
+ (gl_FUNC_LOGB): Invoke it. Set HAVE_LOGB, REPLACE_LOGB.
+ * m4/math_h.m4 (gl_MATH_H_DEFAULTS): Initialize REPLACE_LOGB.
+ * modules/math (Makefile.am): Substitute REPLACE_LOGB.
+ * modules/logb (Files): Add lib/logb.c.
+ (Depends-on): Add isfinite, frexp, isnand.
+ (configure.ac): Compile the replacement code logb.c if needed.
+ * tests/test-math-c++.cc: Check the declaration of logb.
+ * doc/posix-functions/logb.texi: Mention the replacement and the bug
+ with subnormal numbers.
+
+2012-04-02 Bruno Haible <bruno@clisp.org>
+
log10* tests: Speed up.
* tests/test-log10.h (test_function): Reduce amount of random numbers
to test.
diff --git a/doc/posix-functions/logb.texi b/doc/posix-functions/logb.texi
index 3ea333a8bc..799d9a984d 100644
--- a/doc/posix-functions/logb.texi
+++ b/doc/posix-functions/logb.texi
@@ -9,13 +9,16 @@ Gnulib module: logb
Portability problems fixed by Gnulib:
@itemize
@item
+This function is missing on some platforms:
+Minix 3.1.8, MSVC 9.
+@item
This function is missing a declaration on some platforms:
Cygwin 1.5.x.
+@item
+This function produces wrong results for subnormal numbers on some platforms:
+glibc 2.11/ppc, glibc 2.7/sparc, glibc 2.7/hppa, Solaris 11 2011-11, Cygwin 1.5.x.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
-@item
-This function is missing on some platforms:
-Minix 3.1.8, MSVC 9.
@end itemize
diff --git a/lib/logb.c b/lib/logb.c
new file mode 100644
index 0000000000..d56be557a7
--- /dev/null
+++ b/lib/logb.c
@@ -0,0 +1,71 @@
+/* Floating-point exponent.
+ Copyright (C) 2012 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 <http://www.gnu.org/licenses/>. */
+
+#if ! (defined USE_LONG_DOUBLE || defined USE_FLOAT)
+# include <config.h>
+#endif
+
+/* Specification. */
+#include <math.h>
+
+#ifdef USE_LONG_DOUBLE
+# define LOGB logbl
+# define DOUBLE long double
+# define L_(literal) literal##L
+# define HUGEVAL HUGE_VALL
+# define FREXP frexpl
+# define ISNAN isnanl
+#elif ! defined USE_FLOAT
+# define LOGB logb
+# define DOUBLE double
+# define L_(literal) literal
+# define HUGEVAL HUGE_VAL
+# define FREXP frexp
+# define ISNAN isnand
+#else /* defined USE_FLOAT */
+# define LOGB logbf
+# define DOUBLE float
+# define L_(literal) literal##f
+# define HUGEVAL HUGE_VALF
+# define FREXP frexpf
+# define ISNAN isnanf
+#endif
+
+DOUBLE
+LOGB (DOUBLE x)
+{
+ if (isfinite (x))
+ {
+ if (x == L_(0.0))
+ /* Return -Infinity. */
+ return - HUGEVAL;
+ else
+ {
+ int e;
+
+ (void) FREXP (x, &e);
+ return (DOUBLE) (e - 1);
+ }
+ }
+ else
+ {
+ if (ISNAN (x))
+ return x; /* NaN */
+ else
+ /* Return +Infinity. */
+ return HUGEVAL;
+ }
+}
diff --git a/lib/math.in.h b/lib/math.in.h
index f5c5f0391e..40983a9640 100644
--- a/lib/math.in.h
+++ b/lib/math.in.h
@@ -1108,19 +1108,6 @@ _GL_WARN_ON_USE (ldexpl, "ldexpl is unportable - "
#endif
-#if @GNULIB_LOGB@
-# if !@HAVE_DECL_LOGB@
-_GL_EXTERN_C double logb (double x);
-# endif
-#elif defined GNULIB_POSIXCHECK
-# undef logb
-# if HAVE_RAW_DECL_LOGB
-_GL_WARN_ON_USE (logb, "logb is unportable - "
- "use gnulib module logb for portability");
-# endif
-#endif
-
-
#if @GNULIB_LOGF@
# if @REPLACE_LOGF@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -1401,6 +1388,30 @@ _GL_WARN_ON_USE (log2l, "log2l is unportable - "
#endif
+#if @GNULIB_LOGB@
+# if @REPLACE_LOGB@
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef logb
+# define logb rpl_logb
+# endif
+_GL_FUNCDECL_RPL (logb, double, (double x));
+_GL_CXXALIAS_RPL (logb, double, (double x));
+# else
+# if !@HAVE_DECL_LOGB@
+_GL_FUNCDECL_SYS (logb, double, (double x));
+# endif
+_GL_CXXALIAS_SYS (logb, double, (double x));
+# endif
+_GL_CXXALIASWARN (logb);
+#elif defined GNULIB_POSIXCHECK
+# undef logb
+# if HAVE_RAW_DECL_LOGB
+_GL_WARN_ON_USE (logb, "logb is unportable - "
+ "use gnulib module logb for portability");
+# endif
+#endif
+
+
#if @GNULIB_MODFF@
# if @REPLACE_MODFF@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
diff --git a/m4/logb.m4 b/m4/logb.m4
index ee23e243dc..66c9e2a779 100644
--- a/m4/logb.m4
+++ b/m4/logb.m4
@@ -1,4 +1,4 @@
-# logb.m4 serial 5
+# logb.m4 serial 6
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,
@@ -51,8 +51,75 @@ AC_DEFUN([gl_FUNC_LOGB],
[LOGB_LIBM="-lm"])
LIBS="$save_LIBS"
fi
- if test "$LOGB_LIBM" = "?"; then
+ if test "$LOGB_LIBM" != "?"; then
+ HAVE_LOGB=1
+ save_LIBS="$LIBS"
+ LIBS="$LIBS $LOGB_LIBM"
+ gl_FUNC_LOGB_WORKS
+ LIBS="$save_LIBS"
+ case "$gl_cv_func_logb_works" in
+ *yes) ;;
+ *) REPLACE_LOGB=1 ;;
+ esac
+ else
+ HAVE_LOGB=0
+ fi
+ if test $HAVE_LOGB = 0 || test $REPLACE_LOGB = 1; then
+ dnl Find libraries needed to link lib/logb.c.
+ AC_REQUIRE([gl_FUNC_FREXP])
+ AC_REQUIRE([gl_FUNC_ISNAND])
LOGB_LIBM=
+ dnl Append $FREXP_LIBM to LOGB_LIBM, avoiding gratuitous duplicates.
+ case " $LOGB_LIBM " in
+ *" $FREXP_LIBM "*) ;;
+ *) LOGB_LIBM="$LOGB_LIBM $FREXP_LIBM" ;;
+ esac
+ dnl Append $ISNAND_LIBM to LOGB_LIBM, avoiding gratuitous duplicates.
+ case " $LOGB_LIBM " in
+ *" $ISNAND_LIBM "*) ;;
+ *) LOGB_LIBM="$LOGB_LIBM $ISNAND_LIBM" ;;
+ esac
fi
AC_SUBST([LOGB_LIBM])
])
+
+dnl Test whether logb() works.
+dnl On glibc 2.11/ppc, glibc 2.7/sparc, glibc 2.7/hppa, Solaris 10/SPARC,
+dnl Cygwin 1.5.x, the return value for subnormal (denormalized) arguments is
+dnl too large.
+AC_DEFUN([gl_FUNC_LOGB_WORKS],
+[
+ AC_REQUIRE([AC_PROG_CC])
+ AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+ AC_CACHE_CHECK([whether logb works], [gl_cv_func_logb_works],
+ [
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE([[
+#include <float.h>
+#include <math.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+double logb (double);
+volatile double x;
+int main ()
+{
+ int i;
+ for (i = 1, x = 1.0; i >= DBL_MIN_EXP; i--, x *= 0.5)
+ ;
+ /* Here i = DBL_MIN_EXP - 1. Either x = 2^(i-1) is subnormal or x = 0.0. */
+ if (x > 0.0 && !(logb (x) == (double)(i - 1)))
+ return 1;
+ return 0;
+}
+]])],
+ [gl_cv_func_logb_works=yes],
+ [gl_cv_func_logb_works=no],
+ [case "$host_os" in
+ *gnu* | solaris* | cygwin*) gl_cv_func_logb_works="guessing no";;
+ *) gl_cv_func_logb_works="guessing yes";;
+ esac
+ ])
+ ])
+])
diff --git a/m4/math_h.m4 b/m4/math_h.m4
index a24d352892..fe0cd0efaa 100644
--- a/m4/math_h.m4
+++ b/m4/math_h.m4
@@ -1,4 +1,4 @@
-# math_h.m4 serial 107
+# math_h.m4 serial 108
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,
@@ -45,7 +45,8 @@ AC_DEFUN([gl_MATH_H],
fabsf fabsl floorf floorl fma fmaf fmal
fmod fmodf fmodl frexpf frexpl hypotf hypotl
ldexpf ldexpl
- logb log logf logl log10 log10f log10l log1p log1pf log1pl log2 log2f log2l
+ log logf logl log10 log10f log10l log1p log1pf log1pl log2 log2f log2l
+ logb
modf modff modfl powf
remainder remainderf remainderl
rint rintf rintl round roundf roundl sinf sinl sinhf sqrtf sqrtl
@@ -115,7 +116,6 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
GNULIB_ISNANL=0; AC_SUBST([GNULIB_ISNANL])
GNULIB_LDEXPF=0; AC_SUBST([GNULIB_LDEXPF])
GNULIB_LDEXPL=0; AC_SUBST([GNULIB_LDEXPL])
- GNULIB_LOGB=0; AC_SUBST([GNULIB_LOGB])
GNULIB_LOG=0; AC_SUBST([GNULIB_LOG])
GNULIB_LOGF=0; AC_SUBST([GNULIB_LOGF])
GNULIB_LOGL=0; AC_SUBST([GNULIB_LOGL])
@@ -128,6 +128,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
GNULIB_LOG2=0; AC_SUBST([GNULIB_LOG2])
GNULIB_LOG2F=0; AC_SUBST([GNULIB_LOG2F])
GNULIB_LOG2L=0; AC_SUBST([GNULIB_LOG2L])
+ GNULIB_LOGB=0; AC_SUBST([GNULIB_LOGB])
GNULIB_MODF=0; AC_SUBST([GNULIB_MODF])
GNULIB_MODFF=0; AC_SUBST([GNULIB_MODFF])
GNULIB_MODFL=0; AC_SUBST([GNULIB_MODFL])
@@ -227,12 +228,12 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
HAVE_DECL_FLOORL=1; AC_SUBST([HAVE_DECL_FLOORL])
HAVE_DECL_FREXPL=1; AC_SUBST([HAVE_DECL_FREXPL])
HAVE_DECL_LDEXPL=1; AC_SUBST([HAVE_DECL_LDEXPL])
- HAVE_DECL_LOGB=1; AC_SUBST([HAVE_DECL_LOGB])
HAVE_DECL_LOGL=1; AC_SUBST([HAVE_DECL_LOGL])
HAVE_DECL_LOG10L=1; AC_SUBST([HAVE_DECL_LOG10L])
HAVE_DECL_LOG2=1; AC_SUBST([HAVE_DECL_LOG2])
HAVE_DECL_LOG2F=1; AC_SUBST([HAVE_DECL_LOG2F])
HAVE_DECL_LOG2L=1; AC_SUBST([HAVE_DECL_LOG2L])
+ HAVE_DECL_LOGB=1; AC_SUBST([HAVE_DECL_LOGB])
HAVE_DECL_REMAINDER=1; AC_SUBST([HAVE_DECL_REMAINDER])
HAVE_DECL_REMAINDERL=1; AC_SUBST([HAVE_DECL_REMAINDERL])
HAVE_DECL_RINTF=1; AC_SUBST([HAVE_DECL_RINTF])
@@ -287,6 +288,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
REPLACE_LOG2=0; AC_SUBST([REPLACE_LOG2])
REPLACE_LOG2F=0; AC_SUBST([REPLACE_LOG2F])
REPLACE_LOG2L=0; AC_SUBST([REPLACE_LOG2L])
+ REPLACE_LOGB=0; AC_SUBST([REPLACE_LOGB])
REPLACE_MODF=0; AC_SUBST([REPLACE_MODF])
REPLACE_MODFF=0; AC_SUBST([REPLACE_MODFF])
REPLACE_MODFL=0; AC_SUBST([REPLACE_MODFL])
diff --git a/modules/logb b/modules/logb
index 9747473aa1..91df8a4ebe 100644
--- a/modules/logb
+++ b/modules/logb
@@ -2,15 +2,22 @@ Description:
logb() function: get exponent.
Files:
+lib/logb.c
m4/logb.m4
m4/mathfunc.m4
Depends-on:
math
extensions
+isfinite [test $HAVE_LOGB = 0 || test $REPLACE_LOGB = 1]
+frexp [test $HAVE_LOGB = 0 || test $REPLACE_LOGB = 1]
+isnand [test $HAVE_LOGB = 0 || test $REPLACE_LOGB = 1]
configure.ac:
gl_FUNC_LOGB
+if test $HAVE_LOGB = 0 || test $REPLACE_LOGB = 1; then
+ AC_LIBOBJ([logb])
+fi
gl_MATH_MODULE_INDICATOR([logb])
Makefile.am:
diff --git a/modules/math b/modules/math
index 68fe9586fe..26a80b0c0d 100644
--- a/modules/math
+++ b/modules/math
@@ -80,7 +80,6 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
-e 's/@''GNULIB_ISNANL''@/$(GNULIB_ISNANL)/g' \
-e 's/@''GNULIB_LDEXPF''@/$(GNULIB_LDEXPF)/g' \
-e 's/@''GNULIB_LDEXPL''@/$(GNULIB_LDEXPL)/g' \
- -e 's/@''GNULIB_LOGB''@/$(GNULIB_LOGB)/g' \
-e 's/@''GNULIB_LOG''@/$(GNULIB_LOG)/g' \
-e 's/@''GNULIB_LOGF''@/$(GNULIB_LOGF)/g' \
-e 's/@''GNULIB_LOGL''@/$(GNULIB_LOGL)/g' \
@@ -93,6 +92,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
-e 's/@''GNULIB_LOG2''@/$(GNULIB_LOG2)/g' \
-e 's/@''GNULIB_LOG2F''@/$(GNULIB_LOG2F)/g' \
-e 's/@''GNULIB_LOG2L''@/$(GNULIB_LOG2L)/g' \
+ -e 's/@''GNULIB_LOGB''@/$(GNULIB_LOGB)/g' \
-e 's/@''GNULIB_MODF''@/$(GNULIB_MODF)/g' \
-e 's/@''GNULIB_MODFF''@/$(GNULIB_MODFF)/g' \
-e 's/@''GNULIB_MODFL''@/$(GNULIB_MODFL)/g' \
@@ -192,12 +192,12 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
-e 's|@''HAVE_DECL_FLOORL''@|$(HAVE_DECL_FLOORL)|g' \
-e 's|@''HAVE_DECL_FREXPL''@|$(HAVE_DECL_FREXPL)|g' \
-e 's|@''HAVE_DECL_LDEXPL''@|$(HAVE_DECL_LDEXPL)|g' \
- -e 's|@''HAVE_DECL_LOGB''@|$(HAVE_DECL_LOGB)|g' \
-e 's|@''HAVE_DECL_LOGL''@|$(HAVE_DECL_LOGL)|g' \
-e 's|@''HAVE_DECL_LOG10L''@|$(HAVE_DECL_LOG10L)|g' \
-e 's|@''HAVE_DECL_LOG2''@|$(HAVE_DECL_LOG2)|g' \
-e 's|@''HAVE_DECL_LOG2F''@|$(HAVE_DECL_LOG2F)|g' \
-e 's|@''HAVE_DECL_LOG2L''@|$(HAVE_DECL_LOG2L)|g' \
+ -e 's|@''HAVE_DECL_LOGB''@|$(HAVE_DECL_LOGB)|g' \
-e 's|@''HAVE_DECL_REMAINDER''@|$(HAVE_DECL_REMAINDER)|g' \
-e 's|@''HAVE_DECL_REMAINDERL''@|$(HAVE_DECL_REMAINDERL)|g' \
-e 's|@''HAVE_DECL_RINTF''@|$(HAVE_DECL_RINTF)|g' \
@@ -254,6 +254,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
-e 's|@''REPLACE_LOG2''@|$(REPLACE_LOG2)|g' \
-e 's|@''REPLACE_LOG2F''@|$(REPLACE_LOG2F)|g' \
-e 's|@''REPLACE_LOG2L''@|$(REPLACE_LOG2L)|g' \
+ -e 's|@''REPLACE_LOGB''@|$(REPLACE_LOGB)|g' \
-e 's|@''REPLACE_MODF''@|$(REPLACE_MODF)|g' \
-e 's|@''REPLACE_MODFF''@|$(REPLACE_MODFF)|g' \
-e 's|@''REPLACE_MODFL''@|$(REPLACE_MODFL)|g' \
diff --git a/tests/test-math-c++.cc b/tests/test-math-c++.cc
index b6df6595c4..492e54a036 100644
--- a/tests/test-math-c++.cc
+++ b/tests/test-math-c++.cc
@@ -227,8 +227,6 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::log1p, double, (double));
SIGNATURE_CHECK (GNULIB_NAMESPACE::log1pl, long double, (long double));
#endif
-//SIGNATURE_CHECK (GNULIB_NAMESPACE::logb, double, (double));
-
#if GNULIB_TEST_LOGF
SIGNATURE_CHECK (GNULIB_NAMESPACE::logf, float, (float));
#endif
@@ -253,6 +251,10 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::log2, double, (double));
SIGNATURE_CHECK (GNULIB_NAMESPACE::log2l, long double, (long double));
#endif
+#if GNULIB_TEST_LOGB
+SIGNATURE_CHECK (GNULIB_NAMESPACE::logb, double, (double));
+#endif
+
#if GNULIB_TEST_MODFF
SIGNATURE_CHECK (GNULIB_NAMESPACE::modff, float, (float, float *));
#endif