From 181e39ab350fae479c96e345262d7b6a53082923 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 11 Mar 2012 20:50:08 +0100 Subject: [PATCH] New module 'log2l'. * lib/math.in.h (log2l): New declaration. * lib/log2l.c: New file. * m4/log2l.m4: New file. * m4/math_h.m4 (gl_MATH_H): Test whether log2l is declared. (gl_MATH_H_DEFAULTS): Initialize GNULIB_LOG2L, HAVE_DECL_LOG2L, REPLACE_LOG2L. * modules/math (Makefile.am): Substitute GNULIB_LOG2L, HAVE_DECL_LOG2L, REPLACE_LOG2L. * modules/log2l: New file. * tests/test-math-c++.cc: Check the declaration of log2l. * doc/posix-functions/log2l.texi: Mention the new module and the IRIX and OSF/1 problems. --- ChangeLog | 16 ++++++ doc/posix-functions/log2l.texi | 14 ++++-- lib/log2l.c | 85 ++++++++++++++++++++++++++++++++ lib/math.in.h | 23 +++++++++ m4/log2l.m4 | 108 +++++++++++++++++++++++++++++++++++++++++ m4/math_h.m4 | 7 ++- modules/log2l | 35 +++++++++++++ modules/math | 3 ++ tests/test-math-c++.cc | 3 ++ 9 files changed, 288 insertions(+), 6 deletions(-) create mode 100644 lib/log2l.c create mode 100644 m4/log2l.m4 create mode 100644 modules/log2l diff --git a/ChangeLog b/ChangeLog index ab635b1a6..76b7a293f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,21 @@ 2012-03-11 Bruno Haible + New module 'log2l'. + * lib/math.in.h (log2l): New declaration. + * lib/log2l.c: New file. + * m4/log2l.m4: New file. + * m4/math_h.m4 (gl_MATH_H): Test whether log2l is declared. + (gl_MATH_H_DEFAULTS): Initialize GNULIB_LOG2L, HAVE_DECL_LOG2L, + REPLACE_LOG2L. + * modules/math (Makefile.am): Substitute GNULIB_LOG2L, HAVE_DECL_LOG2L, + REPLACE_LOG2L. + * modules/log2l: New file. + * tests/test-math-c++.cc: Check the declaration of log2l. + * doc/posix-functions/log2l.texi: Mention the new module and the IRIX + and OSF/1 problems. + +2012-03-11 Bruno Haible + Tests for module 'log2f'. * modules/log2f-tests: New file. * tests/test-log2f.c: New file. diff --git a/doc/posix-functions/log2l.texi b/doc/posix-functions/log2l.texi index 2db3cbbdd..73491b0de 100644 --- a/doc/posix-functions/log2l.texi +++ b/doc/posix-functions/log2l.texi @@ -4,15 +4,21 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/log2l.html} -Gnulib module: --- +Gnulib module: log2l Portability problems fixed by Gnulib: @itemize +@item +This function is missing on some platforms: +FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, older IRIX 6.5, Solaris 9, Cygwin, MSVC 9, Interix 3.5, BeOS. +@item +This function is not declared on some platforms: +IRIX 6.5. +@item +This function returns a wrong value for a minus zero argument on some platforms: +OSF/1 5.1. @end itemize Portability problems not fixed by Gnulib: @itemize -@item -This function is missing on some platforms: -FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 9, Cygwin, MSVC 9, Interix 3.5, BeOS. @end itemize diff --git a/lib/log2l.c b/lib/log2l.c new file mode 100644 index 000000000..cc69605e7 --- /dev/null +++ b/lib/log2l.c @@ -0,0 +1,85 @@ +/* Base 2 logarithm. + Copyright (C) 2011-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 . */ + +#include + +/* Specification. */ +#include + +#if HAVE_SAME_LONG_DOUBLE_AS_DOUBLE + +long double +log2l (long double x) +{ + return log2 (x); +} + +#else + +/* Best possible approximation of log(2) as a 'long double'. */ +#define LOG2 0.693147180559945309417232121458176568075L + +/* Best possible approximation of 1/log(2) as a 'long double'. */ +#define LOG2_INVERSE 1.44269504088896340735992468100189213743L + +/* sqrt(0.5). */ +#define SQRT_HALF 0.707106781186547524400844362104849039284L + +long double +log2l (long double x) +{ + if (isnanl (x)) + return x; + + if (x <= 0.0L) + { + if (x == 0.0L) + /* Return -Infinity. */ + return - HUGE_VALL; + else + { + /* Return NaN. */ +#if defined _MSC_VER || (defined __sgi && !defined __GNUC__) + static long double zero; + return zero / zero; +#else + return 0.0L / 0.0L; +#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; + long double y; + + y = frexpl (x, &e); + if (y < SQRT_HALF) + { + y = 2.0L * y; + e = e - 1; + } + + return (long double) e + logl (y) * LOG2_INVERSE; + } +} + +#endif diff --git a/lib/math.in.h b/lib/math.in.h index 57b71d55b..77b325399 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -1339,6 +1339,29 @@ _GL_WARN_ON_USE (log2, "log2 is unportable - " # endif #endif +#if @GNULIB_LOG2L@ +# if @REPLACE_LOG2L@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef log2l +# define log2l rpl_log2l +# endif +_GL_FUNCDECL_RPL (log2l, long double, (long double x)); +_GL_CXXALIAS_RPL (log2l, long double, (long double x)); +# else +# if !@HAVE_DECL_LOG2L@ +_GL_FUNCDECL_SYS (log2l, long double, (long double x)); +# endif +_GL_CXXALIAS_SYS (log2l, long double, (long double x)); +# endif +_GL_CXXALIASWARN (log2l); +#elif defined GNULIB_POSIXCHECK +# undef log2l +# if HAVE_RAW_DECL_LOG2L +_GL_WARN_ON_USE (log2l, "log2l is unportable - " + "use gnulib module log2l for portability"); +# endif +#endif + #if @GNULIB_MODFF@ # if @REPLACE_MODFF@ diff --git a/m4/log2l.m4 b/m4/log2l.m4 new file mode 100644 index 000000000..d90a61539 --- /dev/null +++ b/m4/log2l.m4 @@ -0,0 +1,108 @@ +# log2l.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_LOG2L], +[ + AC_REQUIRE([gl_MATH_H_DEFAULTS]) + AC_REQUIRE([gl_LONG_DOUBLE_VS_DOUBLE]) + AC_REQUIRE([gl_FUNC_LOG2]) + + dnl Persuade glibc to declare log2l(). + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + + dnl Test whether log2l() exists. Assume that log2l(), if it exists, is + dnl defined in the same library as log2(). + save_LIBS="$LIBS" + LIBS="$LIBS $LOG2_LIBM" + AC_CHECK_FUNCS([log2l]) + LIBS="$save_LIBS" + if test $ac_cv_func_log2l = yes; then + LOG2L_LIBM="$LOG2_LIBM" + HAVE_LOG2L=1 + dnl Also check whether it's declared. + dnl IRIX 6.5 has log2l() in libm but doesn't declare it in . + AC_CHECK_DECL([log2l], , [HAVE_DECL_LOG2L=0], [[#include ]]) + + save_LIBS="$LIBS" + LIBS="$LIBS $LOG2L_LIBM" + gl_FUNC_LOG2L_WORKS + LIBS="$save_LIBS" + case "$gl_cv_func_log2l_works" in + *yes) ;; + *) REPLACE_LOG2L=1 ;; + esac + else + HAVE_LOG2L=0 + HAVE_DECL_LOG2L=0 + fi + if test $HAVE_LOG2L = 0 || test $REPLACE_LOG2L = 1; then + dnl Find libraries needed to link lib/log2l.c. + if test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1; then + LOG2L_LIBM="$LOG2_LIBM" + else + AC_REQUIRE([gl_FUNC_ISNANL]) + AC_REQUIRE([gl_FUNC_FREXPL]) + AC_REQUIRE([gl_FUNC_LOGL]) + LOG2L_LIBM= + dnl Append $ISNANL_LIBM to LOG2L_LIBM, avoiding gratuitous duplicates. + case " $LOG2L_LIBM " in + *" $ISNANL_LIBM "*) ;; + *) LOG2L_LIBM="$LOG2L_LIBM $ISNANL_LIBM" ;; + esac + dnl Append $FREXPL_LIBM to LOG2L_LIBM, avoiding gratuitous duplicates. + case " $LOG2L_LIBM " in + *" $FREXPL_LIBM "*) ;; + *) LOG2L_LIBM="$LOG2L_LIBM $FREXPL_LIBM" ;; + esac + dnl Append $LOGL_LIBM to LOG2L_LIBM, avoiding gratuitous duplicates. + case " $LOG2L_LIBM " in + *" $LOGL_LIBM "*) ;; + *) LOG2L_LIBM="$LOG2L_LIBM $LOGL_LIBM" ;; + esac + fi + fi + AC_SUBST([LOG2L_LIBM]) +]) + +dnl Test whether log2l() works. +dnl On OSF/1 5.1, log2l(-0.0) is NaN. +AC_DEFUN([gl_FUNC_LOG2L_WORKS], +[ + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether log2l works], [gl_cv_func_log2l_works], + [ + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#ifndef log2l /* for AIX */ +extern +#ifdef __cplusplus +"C" +#endif +long double log2l (long double); +#endif +volatile long double x; +volatile long double y; +int main () +{ + /* This test fails on OSF/1 5.1. */ + x = -0.0L; + y = log2l (x); + if (!(y + y == y)) + return 1; + return 0; +} +]])], + [gl_cv_func_log2l_works=yes], + [gl_cv_func_log2l_works=no], + [case "$host_os" in + osf*) gl_cv_func_log2l_works="guessing no";; + *) gl_cv_func_log2l_works="guessing yes";; + esac + ]) + ]) +]) diff --git a/m4/math_h.m4 b/m4/math_h.m4 index ec1534026..d48fd9735 100644 --- a/m4/math_h.m4 +++ b/m4/math_h.m4 @@ -1,4 +1,4 @@ -# math_h.m4 serial 102 +# math_h.m4 serial 103 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,7 @@ 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 log10f log10l log1p log1pf log1pl log2 log2f + logb log logf logl log10f log10l log1p log1pf log1pl log2 log2f log2l modf modff modfl powf remainder remainderf remainderl rint rintf rintl round roundf roundl sinf sinl sinhf sqrtf sqrtl @@ -126,6 +126,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], GNULIB_LOG1PL=0; AC_SUBST([GNULIB_LOG1PL]) GNULIB_LOG2=0; AC_SUBST([GNULIB_LOG2]) GNULIB_LOG2F=0; AC_SUBST([GNULIB_LOG2F]) + GNULIB_LOG2L=0; AC_SUBST([GNULIB_LOG2L]) GNULIB_MODF=0; AC_SUBST([GNULIB_MODF]) GNULIB_MODFF=0; AC_SUBST([GNULIB_MODFF]) GNULIB_MODFL=0; AC_SUBST([GNULIB_MODFL]) @@ -230,6 +231,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], 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_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]) @@ -280,6 +282,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], REPLACE_LOG1PL=0; AC_SUBST([REPLACE_LOG1PL]) REPLACE_LOG2=0; AC_SUBST([REPLACE_LOG2]) REPLACE_LOG2F=0; AC_SUBST([REPLACE_LOG2F]) + REPLACE_LOG2L=0; AC_SUBST([REPLACE_LOG2L]) 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/log2l b/modules/log2l new file mode 100644 index 000000000..848f6d4f0 --- /dev/null +++ b/modules/log2l @@ -0,0 +1,35 @@ +Description: +log2() function: base 2 logarithm. + +Files: +lib/log2l.c +m4/log2l.m4 + +Depends-on: +math +extensions +log2 [{ test $HAVE_LOG2L = 0 || test $REPLACE_LOG2L = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1] +isnanl [{ test $HAVE_LOG2L = 0 || test $REPLACE_LOG2L = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] +frexpl [{ test $HAVE_LOG2L = 0 || test $REPLACE_LOG2L = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] +logl [{ test $HAVE_LOG2L = 0 || test $REPLACE_LOG2L = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0] + +configure.ac: +gl_FUNC_LOG2L +if test $HAVE_LOG2L = 0 || test $REPLACE_LOG2L = 1; then + AC_LIBOBJ([log2l]) +fi +gl_MATH_MODULE_INDICATOR([log2l]) + +Makefile.am: + +Include: + + +Link: +$(LOG2L_LIBM) + +License: +LGPL + +Maintainer: +Bruno Haible diff --git a/modules/math b/modules/math index 7382974a7..46d0455a5 100644 --- a/modules/math +++ b/modules/math @@ -91,6 +91,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's/@''GNULIB_LOG1PL''@/$(GNULIB_LOG1PL)/g' \ -e 's/@''GNULIB_LOG2''@/$(GNULIB_LOG2)/g' \ -e 's/@''GNULIB_LOG2F''@/$(GNULIB_LOG2F)/g' \ + -e 's/@''GNULIB_LOG2L''@/$(GNULIB_LOG2L)/g' \ -e 's/@''GNULIB_MODF''@/$(GNULIB_MODF)/g' \ -e 's/@''GNULIB_MODFF''@/$(GNULIB_MODFF)/g' \ -e 's/@''GNULIB_MODFL''@/$(GNULIB_MODFL)/g' \ @@ -195,6 +196,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -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_REMAINDER''@|$(HAVE_DECL_REMAINDER)|g' \ -e 's|@''HAVE_DECL_REMAINDERL''@|$(HAVE_DECL_REMAINDERL)|g' \ -e 's|@''HAVE_DECL_RINTF''@|$(HAVE_DECL_RINTF)|g' \ @@ -247,6 +249,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''REPLACE_LOG1PL''@|$(REPLACE_LOG1PL)|g' \ -e 's|@''REPLACE_LOG2''@|$(REPLACE_LOG2)|g' \ -e 's|@''REPLACE_LOG2F''@|$(REPLACE_LOG2F)|g' \ + -e 's|@''REPLACE_LOG2L''@|$(REPLACE_LOG2L)|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 635145807..9caa9511e 100644 --- a/tests/test-math-c++.cc +++ b/tests/test-math-c++.cc @@ -247,6 +247,9 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::log2f, float, (float)); #if GNULIB_TEST_LOG2 SIGNATURE_CHECK (GNULIB_NAMESPACE::log2, double, (double)); #endif +#if GNULIB_TEST_LOG2L +SIGNATURE_CHECK (GNULIB_NAMESPACE::log2l, long double, (long double)); +#endif #if GNULIB_TEST_MODFF SIGNATURE_CHECK (GNULIB_NAMESPACE::modff, float, (float, float *)); -- 2.11.0