* lib/math.in.h (log2): New declaration.
* lib/log2.c: New file.
* m4/log2.m4: New file.
* m4/math_h.m4 (gl_MATH_H): Test whether log2 is declared.
(gl_MATH_H_DEFAULTS): Initialize GNULIB_LOG2, HAVE_DECL_LOG2,
REPLACE_LOG2.
* modules/math (Makefile.am): Substitute GNULIB_LOG2, HAVE_DECL_LOG2,
REPLACE_LOG2.
* modules/log2: New file.
* tests/test-math-c++.cc: Check the declaration of log2.
* doc/posix-functions/log2.texi: Mention the new module and the IRIX
and OSF/1 and Cygwin problems.
+2012-03-11 Bruno Haible <bruno@clisp.org>
+
+ New module 'log2'.
+ * lib/math.in.h (log2): New declaration.
+ * lib/log2.c: New file.
+ * m4/log2.m4: New file.
+ * m4/math_h.m4 (gl_MATH_H): Test whether log2 is declared.
+ (gl_MATH_H_DEFAULTS): Initialize GNULIB_LOG2, HAVE_DECL_LOG2,
+ REPLACE_LOG2.
+ * modules/math (Makefile.am): Substitute GNULIB_LOG2, HAVE_DECL_LOG2,
+ REPLACE_LOG2.
+ * modules/log2: New file.
+ * tests/test-math-c++.cc: Check the declaration of log2.
+ * doc/posix-functions/log2.texi: Mention the new module and the IRIX
+ and OSF/1 and Cygwin problems.
+
2012-03-11 Bruno Haible <bruno@clisp.org>
exp2* tests: More tests.
POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/log2.html}
-Gnulib module: ---
+Gnulib module: log2
Portability problems fixed by Gnulib:
@itemize
-@end itemize
-
-Portability problems not fixed by Gnulib:
-@itemize
@item
This function is missing on some platforms:
-FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, IRIX 6.5,
+FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, older IRIX 6.5,
Solaris 9, MSVC 9, Interix 3.5.
@item
+This function is not declared on some platforms:
+IRIX 6.5.
+@item
This function is only provided as a macro on some platforms:
Cygwin 1.5.x.
+@item
+This function returns a wrong value for a minus zero argument on some platforms:
+OSF/1 5.1.
+@item
+This function returns slightly wrong values for exact powers of 2 on some platforms:
+Cygwin 1.7.9.
+@end itemize
+
+Portability problems not fixed by Gnulib:
+@itemize
@end itemize
--- /dev/null
+/* Base 2 logarithm.
+ 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/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include <math.h>
+
+/* Best possible approximation of log(2) as a 'double'. */
+#define LOG2 0.693147180559945309417232121458176568075
+
+/* Best possible approximation of 1/log(2) as a 'double'. */
+#define LOG2_INVERSE 1.44269504088896340735992468100189213743
+
+/* sqrt(0.5). */
+#define SQRT_HALF 0.707106781186547524400844362104849039284
+
+double
+log2 (double x)
+{
+ if (isnand (x))
+ return x;
+
+ if (x <= 0.0)
+ {
+ if (x == 0.0)
+ /* Return -Infinity. */
+ return - HUGE_VAL;
+ else
+ {
+ /* Return NaN. */
+#if defined _MSC_VER || (defined __sgi && !defined __GNUC__)
+ static double zero;
+ return zero / zero;
+#else
+ return 0.0 / 0.0;
+#endif
+ }
+ }
+
+ /* Decompose x into
+ x = 2^e * y
+ where
+ e is an integer,
+ 1/2 < y < 2.
+ Then log2(x) = e + log2(y) = e + log(y)/log(2). */
+ {
+ int e;
+ double y;
+
+ y = frexp (x, &e);
+ if (y < SQRT_HALF)
+ {
+ y = 2.0 * y;
+ e = e - 1;
+ }
+
+ return (double) e + log (y) * LOG2_INVERSE;
+ }
+}
#endif
+#if @GNULIB_LOG2@
+# if @REPLACE_LOG2@
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef log2
+# define log2 rpl_log2
+# endif
+_GL_FUNCDECL_RPL (log2, double, (double x));
+_GL_CXXALIAS_RPL (log2, double, (double x));
+# else
+# if !@HAVE_DECL_LOG2@
+# undef log2
+_GL_FUNCDECL_SYS (log2, double, (double x));
+# endif
+_GL_CXXALIAS_SYS (log2, double, (double x));
+# endif
+_GL_CXXALIASWARN (log2);
+#elif defined GNULIB_POSIXCHECK
+# undef log2
+# if HAVE_RAW_DECL_LOG2
+_GL_WARN_ON_USE (log2, "log2 is unportable - "
+ "use gnulib module log2 for portability");
+# endif
+#endif
+
+
#if @GNULIB_MODFF@
# if @REPLACE_MODFF@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
--- /dev/null
+# log2.m4 serial 1
+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,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_LOG2],
+[
+ AC_REQUIRE([gl_MATH_H_DEFAULTS])
+
+ dnl Persuade glibc <math.h> to declare log2().
+ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+
+ dnl Determine LOG2_LIBM.
+ gl_COMMON_DOUBLE_MATHFUNC([log2])
+
+ dnl Test whether log2() exists.
+ save_LIBS="$LIBS"
+ LIBS="$LIBS $LOG2_LIBM"
+ AC_CHECK_FUNCS([log2])
+ LIBS="$save_LIBS"
+ if test $ac_cv_func_log2 = yes; then
+ HAVE_LOG2=1
+ dnl Also check whether it's declared.
+ dnl IRIX 6.5 has log2() in libm but doesn't declare it in <math.h>.
+ AC_CHECK_DECL([log2], , [HAVE_DECL_LOG2=0], [[#include <math.h>]])
+
+ save_LIBS="$LIBS"
+ LIBS="$LIBS $LOG2_LIBM"
+ gl_FUNC_LOG2_WORKS
+ LIBS="$save_LIBS"
+ case "$gl_cv_func_log2_works" in
+ *yes) ;;
+ *) REPLACE_LOG2=1 ;;
+ esac
+ else
+ HAVE_LOG2=0
+ HAVE_DECL_LOG2=0
+ fi
+ if test $HAVE_LOG2 = 0 || test $REPLACE_LOG2 = 1; then
+ dnl Find libraries needed to link lib/log2.c.
+ AC_REQUIRE([gl_FUNC_ISNAND])
+ AC_REQUIRE([gl_FUNC_FREXP])
+ AC_REQUIRE([gl_FUNC_LOG])
+ LOG2_LIBM=
+ dnl Append $ISNAND_LIBM to LOG2_LIBM, avoiding gratuitous duplicates.
+ case " $LOG2_LIBM " in
+ *" $ISNAND_LIBM "*) ;;
+ *) LOG2_LIBM="$LOG2_LIBM $ISNAND_LIBM" ;;
+ esac
+ dnl Append $FREXP_LIBM to LOG2_LIBM, avoiding gratuitous duplicates.
+ case " $LOG2_LIBM " in
+ *" $FREXP_LIBM "*) ;;
+ *) LOG2_LIBM="$LOG2_LIBM $FREXP_LIBM" ;;
+ esac
+ dnl Append $LOG_LIBM to LOG2_LIBM, avoiding gratuitous duplicates.
+ case " $LOG2_LIBM " in
+ *" $LOG_LIBM "*) ;;
+ *) LOG2_LIBM="$LOG2_LIBM $LOG_LIBM" ;;
+ esac
+ fi
+])
+
+dnl Test whether log2() works.
+dnl On OSF/1 5.1, log2(-0.0) is NaN.
+dnl On Cygwin 1.7.9, log2(2^29) is not exactly 29.
+AC_DEFUN([gl_FUNC_LOG2_WORKS],
+[
+ AC_REQUIRE([AC_PROG_CC])
+ AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+ AC_CACHE_CHECK([whether log2 works], [gl_cv_func_log2_works],
+ [
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE([[
+#include <math.h>
+#ifndef log2 /* for Cygwin 1.7.x */
+extern
+#ifdef __cplusplus
+"C"
+#endif
+double log2 (double);
+#endif
+volatile double x;
+volatile double y;
+int main ()
+{
+ int result = 0;
+ /* This test fails on OSF/1 5.1. */
+ x = -0.0;
+ y = log2 (x);
+ if (!(y + y == y))
+ result |= 1;
+ /* This test fails on Cygwin 1.7.9. */
+ x = 536870912.0;
+ y = log2 (x);
+ if (!(y == 29.0))
+ result |= 2;
+ return result;
+}
+]])],
+ [gl_cv_func_log2_works=yes],
+ [gl_cv_func_log2_works=no],
+ [case "$host_os" in
+ cygwin* | osf*) gl_cv_func_log2_works="guessing no";;
+ *) gl_cv_func_log2_works="guessing yes";;
+ esac
+ ])
+ ])
+])
-# math_h.m4 serial 100
+# math_h.m4 serial 101
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,
expf expl exp2 exp2f exp2l expm1 expm1f expm1l
fabsf fabsl floorf floorl fma fmaf fmal
fmod fmodf fmodl frexpf frexpl hypotf hypotl
- ldexpf ldexpl logb log logf logl log10f log10l log1p log1pf log1pl
+ ldexpf ldexpl logb log logf logl log10f log10l log1p log1pf log1pl log2
modf modff modfl powf
remainder remainderf remainderl
rint rintf rintl round roundf roundl sinf sinl sinhf sqrtf sqrtl
GNULIB_LOG1P=0; AC_SUBST([GNULIB_LOG1P])
GNULIB_LOG1PF=0; AC_SUBST([GNULIB_LOG1PF])
GNULIB_LOG1PL=0; AC_SUBST([GNULIB_LOG1PL])
+ GNULIB_LOG2=0; AC_SUBST([GNULIB_LOG2])
GNULIB_MODF=0; AC_SUBST([GNULIB_MODF])
GNULIB_MODFF=0; AC_SUBST([GNULIB_MODFF])
GNULIB_MODFL=0; AC_SUBST([GNULIB_MODFL])
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_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])
REPLACE_LOG1P=0; AC_SUBST([REPLACE_LOG1P])
REPLACE_LOG1PF=0; AC_SUBST([REPLACE_LOG1PF])
REPLACE_LOG1PL=0; AC_SUBST([REPLACE_LOG1PL])
+ REPLACE_LOG2=0; AC_SUBST([REPLACE_LOG2])
REPLACE_MODF=0; AC_SUBST([REPLACE_MODF])
REPLACE_MODFF=0; AC_SUBST([REPLACE_MODFF])
REPLACE_MODFL=0; AC_SUBST([REPLACE_MODFL])
--- /dev/null
+Description:
+log2() function: base 2 logarithm.
+
+Files:
+lib/log2.c
+m4/log2.m4
+m4/mathfunc.m4
+
+Depends-on:
+math
+extensions
+isnand [test $HAVE_LOG2 = 0 || test $REPLACE_LOG2 = 1]
+frexp [test $HAVE_LOG2 = 0 || test $REPLACE_LOG2 = 1]
+log [test $HAVE_LOG2 = 0 || test $REPLACE_LOG2 = 1]
+
+configure.ac:
+gl_FUNC_LOG2
+if test $HAVE_LOG2 = 0 || test $REPLACE_LOG2 = 1; then
+ AC_LIBOBJ([log2])
+fi
+gl_MATH_MODULE_INDICATOR([log2])
+
+Makefile.am:
+
+Include:
+<math.h>
+
+Link:
+$(LOG2_LIBM)
+
+License:
+LGPL
+
+Maintainer:
+Bruno Haible
-e 's/@''GNULIB_LOG1P''@/$(GNULIB_LOG1P)/g' \
-e 's/@''GNULIB_LOG1PF''@/$(GNULIB_LOG1PF)/g' \
-e 's/@''GNULIB_LOG1PL''@/$(GNULIB_LOG1PL)/g' \
+ -e 's/@''GNULIB_LOG2''@/$(GNULIB_LOG2)/g' \
-e 's/@''GNULIB_MODF''@/$(GNULIB_MODF)/g' \
-e 's/@''GNULIB_MODFF''@/$(GNULIB_MODFF)/g' \
-e 's/@''GNULIB_MODFL''@/$(GNULIB_MODFL)/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_REMAINDER''@|$(HAVE_DECL_REMAINDER)|g' \
-e 's|@''HAVE_DECL_REMAINDERL''@|$(HAVE_DECL_REMAINDERL)|g' \
-e 's|@''HAVE_DECL_RINTF''@|$(HAVE_DECL_RINTF)|g' \
-e 's|@''REPLACE_LOG1P''@|$(REPLACE_LOG1P)|g' \
-e 's|@''REPLACE_LOG1PF''@|$(REPLACE_LOG1PF)|g' \
-e 's|@''REPLACE_LOG1PL''@|$(REPLACE_LOG1PL)|g' \
+ -e 's|@''REPLACE_LOG2''@|$(REPLACE_LOG2)|g' \
-e 's|@''REPLACE_MODF''@|$(REPLACE_MODF)|g' \
-e 's|@''REPLACE_MODFF''@|$(REPLACE_MODFF)|g' \
-e 's|@''REPLACE_MODFL''@|$(REPLACE_MODFL)|g' \
SIGNATURE_CHECK (GNULIB_NAMESPACE::log10f, float, (float));
#endif
+#if GNULIB_TEST_LOG2
+SIGNATURE_CHECK (GNULIB_NAMESPACE::log2, double, (double));
+#endif
+
#if GNULIB_TEST_MODFF
SIGNATURE_CHECK (GNULIB_NAMESPACE::modff, float, (float, float *));
#endif