From 1ab17d9f64900d991443e712f636c9ef6ad543b2 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Tue, 3 Apr 2012 18:59:33 +0200 Subject: [PATCH] New module 'ilogb'. * lib/math.in.h (ilogb): New declaration. * lib/ilogb.c: New file. * m4/ilogb.m4: New file. * m4/math_h.m4 (gl_MATH_H): Test whether ilogb is declared. (gl_MATH_H_DEFAULTS): Initialize GNULIB_ILOGB, HAVE_ILOGB, REPLACE_ILOGB. * modules/math (Makefile.am): Substitute GNULIB_ILOGB, HAVE_ILOGB, REPLACE_ILOGB. * modules/ilogb: New file. * tests/test-math-c++.cc: Check the declaration of ilogb. * doc/posix-functions/ilogb.texi: Mention the new module. --- ChangeLog | 15 ++++++ doc/posix-functions/ilogb.texi | 17 +++++-- lib/ilogb.c | 68 +++++++++++++++++++++++++ lib/math.in.h | 24 +++++++++ m4/ilogb.m4 | 112 +++++++++++++++++++++++++++++++++++++++++ m4/math_h.m4 | 6 ++- modules/ilogb | 34 +++++++++++++ modules/math | 3 ++ tests/test-math-c++.cc | 4 ++ 9 files changed, 278 insertions(+), 5 deletions(-) create mode 100644 lib/ilogb.c create mode 100644 m4/ilogb.m4 create mode 100644 modules/ilogb diff --git a/ChangeLog b/ChangeLog index 00493ceca..e63048391 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,20 @@ 2012-04-03 Bruno Haible + New module 'ilogb'. + * lib/math.in.h (ilogb): New declaration. + * lib/ilogb.c: New file. + * m4/ilogb.m4: New file. + * m4/math_h.m4 (gl_MATH_H): Test whether ilogb is declared. + (gl_MATH_H_DEFAULTS): Initialize GNULIB_ILOGB, HAVE_ILOGB, + REPLACE_ILOGB. + * modules/math (Makefile.am): Substitute GNULIB_ILOGB, HAVE_ILOGB, + REPLACE_ILOGB. + * modules/ilogb: New file. + * tests/test-math-c++.cc: Check the declaration of ilogb. + * doc/posix-functions/ilogb.texi: Mention the new module. + +2012-04-03 Bruno Haible + math: Provide FP_ILOGB0 and FP_ILOGBNAN. * lib/math.in.h (FP_ILOGB0, FP_ILOGBNAN): Define fallback. * tests/test-math.c: Check that FP_ILOGB0, FP_ILOGBNAN are defined. diff --git a/doc/posix-functions/ilogb.texi b/doc/posix-functions/ilogb.texi index 1005db682..3b1a4eb1a 100644 --- a/doc/posix-functions/ilogb.texi +++ b/doc/posix-functions/ilogb.texi @@ -4,15 +4,24 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/ilogb.html} -Gnulib module: --- +Gnulib module: ilogb Portability problems fixed by Gnulib: @itemize +@item +This function is missing on some platforms: +Minix 3.1.8, IRIX 5.3, MSVC 9. +@item +This function returns a wrong result for a zero argument on some platforms: +OpenBSD 4.9, AIX 5.1. +@item +This function returns a wrong result for an infinite argument on some platforms: +NetBSD 5.1, OpenBSD 4.9. +@item +This function returns a wrong result for a NaN argument on some platforms: +OpenBSD 4.9. @end itemize Portability problems not fixed by Gnulib: @itemize -@item -This function is missing on some platforms: -Minix 3.1.8, IRIX 5.3, MSVC 9. @end itemize diff --git a/lib/ilogb.c b/lib/ilogb.c new file mode 100644 index 000000000..2b92a0889 --- /dev/null +++ b/lib/ilogb.c @@ -0,0 +1,68 @@ +/* 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 . */ + +#if ! (defined USE_LONG_DOUBLE || defined USE_FLOAT) +# include +#endif + +/* Specification. */ +#include + +#include + +#ifdef USE_LONG_DOUBLE +# define ILOGB ilogbl +# define DOUBLE long double +# define L_(literal) literal##L +# define FREXP frexpl +# define ISNAN isnanl +#elif ! defined USE_FLOAT +# define ILOGB ilogb +# define DOUBLE double +# define L_(literal) literal +# define FREXP frexp +# define ISNAN isnand +#else /* defined USE_FLOAT */ +# define ILOGB ilogbf +# define DOUBLE float +# define L_(literal) literal##f +# define FREXP frexpf +# define ISNAN isnanf +#endif + +int +ILOGB (DOUBLE x) +{ + if (isfinite (x)) + { + if (x == L_(0.0)) + return FP_ILOGB0; + else + { + int e; + + (void) FREXP (x, &e); + return e - 1; + } + } + else + { + if (ISNAN (x)) + return FP_ILOGBNAN; + else + return INT_MAX; + } +} diff --git a/lib/math.in.h b/lib/math.in.h index b87aacb7b..83ba3476b 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -1087,6 +1087,30 @@ _GL_WARN_ON_USE (hypotl, "hypotl is unportable - " #endif +#if @GNULIB_ILOGB@ +# if @REPLACE_ILOGB@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef ilogb +# define ilogb rpl_ilogb +# endif +_GL_FUNCDECL_RPL (ilogb, int, (double x)); +_GL_CXXALIAS_RPL (ilogb, int, (double x)); +# else +# if !@HAVE_ILOGB@ +_GL_FUNCDECL_SYS (ilogb, int, (double x)); +# endif +_GL_CXXALIAS_SYS (ilogb, int, (double x)); +# endif +_GL_CXXALIASWARN (ilogb); +#elif defined GNULIB_POSIXCHECK +# undef ilogb +# if HAVE_RAW_DECL_ILOGB +_GL_WARN_ON_USE (ilogb, "ilogb is unportable - " + "use gnulib module ilogb for portability"); +# endif +#endif + + /* Return x * 2^exp. */ #if @GNULIB_LDEXPF@ # if !@HAVE_LDEXPF@ diff --git a/m4/ilogb.m4 b/m4/ilogb.m4 new file mode 100644 index 000000000..8e9c05ffb --- /dev/null +++ b/m4/ilogb.m4 @@ -0,0 +1,112 @@ +# ilogb.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_ILOGB], +[ + AC_REQUIRE([gl_MATH_H_DEFAULTS]) + + dnl Determine ILOGB_LIBM. + gl_MATHFUNC([ilogb], [int], [(double)]) + if test $gl_cv_func_ilogb_no_libm = yes \ + || test $gl_cv_func_ilogb_in_libm = yes; then + save_LIBS="$LIBS" + LIBS="$LIBS $ILOGB_LIBM" + gl_FUNC_ILOGB_WORKS + LIBS="$save_LIBS" + case "$gl_cv_func_ilogb_works" in + *yes) ;; + *) REPLACE_ILOGB=1 ;; + esac + else + HAVE_ILOGB=0 + fi + if test $HAVE_ILOGB = 0 || test $REPLACE_ILOGB = 1; then + dnl Find libraries needed to link lib/ilogb.c. + AC_REQUIRE([gl_FUNC_FREXP]) + AC_REQUIRE([gl_FUNC_ISNAND]) + ILOGB_LIBM= + dnl Append $FREXP_LIBM to ILOGB_LIBM, avoiding gratuitous duplicates. + case " $ILOGB_LIBM " in + *" $FREXP_LIBM "*) ;; + *) ILOGB_LIBM="$ILOGB_LIBM $FREXP_LIBM" ;; + esac + dnl Append $ISNAND_LIBM to ILOGB_LIBM, avoiding gratuitous duplicates. + case " $ILOGB_LIBM " in + *" $ISNAND_LIBM "*) ;; + *) ILOGB_LIBM="$ILOGB_LIBM $ISNAND_LIBM" ;; + esac + fi + AC_SUBST([ILOGB_LIBM]) +]) + +dnl Test whether ilogb() works. +dnl On OpenBSD 4.9, AIX 5.1, ilogb(0.0) is wrong. +dnl On NetBSD 5.1, OpenBSD 4.9, ilogb(Infinity) is wrong. +dnl On OpenBSD 4.9, ilogb(NaN) is wrong. +AC_DEFUN([gl_FUNC_ILOGB_WORKS], +[ + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether ilogb works], [gl_cv_func_ilogb_works], + [ + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#include +/* Provide FP_ILOGB0, FP_ILOGBNAN, like in math.in.h. */ +#if !(defined FP_ILOGB0 && defined FP_ILOGBNAN) +# if defined __NetBSD__ || defined __sgi + /* NetBSD, IRIX 6.5: match what ilogb() does */ +# define FP_ILOGB0 INT_MIN +# define FP_ILOGBNAN INT_MIN +# elif defined _AIX + /* AIX 5.1: match what ilogb() does in AIX >= 5.2 */ +# define FP_ILOGB0 INT_MIN +# define FP_ILOGBNAN INT_MAX +# elif defined __sun + /* Solaris 9: match what ilogb() does */ +# define FP_ILOGB0 (- INT_MAX) +# define FP_ILOGBNAN INT_MAX +# endif +#endif +volatile double x; +static double zero; +static int dummy (double x) { return 0; } +int main (int argc, char *argv[]) +{ + int (*my_ilogb) (double) = argc ? ilogb : dummy; + int result = 0; + /* This test fails on OpenBSD 4.9, AIX 5.1. */ + { + x = 0.0; + if (my_ilogb (x) != FP_ILOGB0) + result |= 1; + } + /* This test fails on NetBSD 5.1, OpenBSD 4.9. */ + { + x = 1.0 / zero; + if (my_ilogb (x) != INT_MAX) + result |= 2; + } + /* This test fails on OpenBSD 4.9. */ + { + x = zero / zero; + if (my_ilogb (x) != FP_ILOGBNAN) + result |= 4; + } + return result; +} +]])], + [gl_cv_func_ilogb_works=yes], + [gl_cv_func_ilogb_works=no], + [case "$host_os" in + aix* | openbsd* | netbsd* | solaris*) + gl_cv_func_ilogb_works="guessing no";; + *) gl_cv_func_ilogb_works="guessing yes";; + esac + ]) + ]) +]) diff --git a/m4/math_h.m4 b/m4/math_h.m4 index ef97a600d..d9735df13 100644 --- a/m4/math_h.m4 +++ b/m4/math_h.m4 @@ -1,4 +1,4 @@ -# math_h.m4 serial 110 +# math_h.m4 serial 111 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, @@ -44,6 +44,7 @@ AC_DEFUN([gl_MATH_H], expf expl exp2 exp2f exp2l expm1 expm1f expm1l fabsf fabsl floorf floorl fma fmaf fmal fmod fmodf fmodl frexpf frexpl hypotf hypotl + ilogb ldexpf ldexpl log logf logl log10 log10f log10l log1p log1pf log1pl log2 log2f log2l logb logbf logbl @@ -108,6 +109,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], GNULIB_HYPOT=0; AC_SUBST([GNULIB_HYPOT]) GNULIB_HYPOTF=0; AC_SUBST([GNULIB_HYPOTF]) GNULIB_HYPOTL=0; AC_SUBST([GNULIB_HYPOTL]) + GNULIB_ILOGB=0; AC_SUBST([GNULIB_ILOGB]) GNULIB_ISFINITE=0; AC_SUBST([GNULIB_ISFINITE]) GNULIB_ISINF=0; AC_SUBST([GNULIB_ISINF]) GNULIB_ISNAN=0; AC_SUBST([GNULIB_ISNAN]) @@ -186,6 +188,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], HAVE_FREXPF=1; AC_SUBST([HAVE_FREXPF]) HAVE_HYPOTF=1; AC_SUBST([HAVE_HYPOTF]) HAVE_HYPOTL=1; AC_SUBST([HAVE_HYPOTL]) + HAVE_ILOGB=1; AC_SUBST([HAVE_ILOGB]) HAVE_ISNANF=1; AC_SUBST([HAVE_ISNANF]) HAVE_ISNAND=1; AC_SUBST([HAVE_ISNAND]) HAVE_ISNANL=1; AC_SUBST([HAVE_ISNANL]) @@ -276,6 +279,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], REPLACE_HYPOT=0; AC_SUBST([REPLACE_HYPOT]) REPLACE_HYPOTF=0; AC_SUBST([REPLACE_HYPOTF]) REPLACE_HYPOTL=0; AC_SUBST([REPLACE_HYPOTL]) + REPLACE_ILOGB=0; AC_SUBST([REPLACE_ILOGB]) REPLACE_ISFINITE=0; AC_SUBST([REPLACE_ISFINITE]) REPLACE_ISINF=0; AC_SUBST([REPLACE_ISINF]) REPLACE_ISNAN=0; AC_SUBST([REPLACE_ISNAN]) diff --git a/modules/ilogb b/modules/ilogb new file mode 100644 index 000000000..92adb5749 --- /dev/null +++ b/modules/ilogb @@ -0,0 +1,34 @@ +Description: +ilogb() function: get exponent as integer. + +Files: +lib/ilogb.c +m4/ilogb.m4 +m4/mathfunc.m4 + +Depends-on: +math +isfinite [test $HAVE_ILOGB = 0 || test $REPLACE_ILOGB = 1] +frexp [test $HAVE_ILOGB = 0 || test $REPLACE_ILOGB = 1] +isnand [test $HAVE_ILOGB = 0 || test $REPLACE_ILOGB = 1] + +configure.ac: +gl_FUNC_ILOGB +if test $HAVE_ILOGB = 0 || test $REPLACE_ILOGB = 1; then + AC_LIBOBJ([ilogb]) +fi +gl_MATH_MODULE_INDICATOR([ilogb]) + +Makefile.am: + +Include: + + +Link: +$(ILOGB_LIBM) + +License: +LGPL + +Maintainer: +Bruno Haible diff --git a/modules/math b/modules/math index b83edfd22..3b7cbd66d 100644 --- a/modules/math +++ b/modules/math @@ -72,6 +72,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's/@''GNULIB_HYPOT''@/$(GNULIB_HYPOT)/g' \ -e 's/@''GNULIB_HYPOTF''@/$(GNULIB_HYPOTF)/g' \ -e 's/@''GNULIB_HYPOTL''@/$(GNULIB_HYPOTL)/g' \ + -e 's/@''GNULIB_ILOGB''@/$(GNULIB_ILOGB)/g' \ -e 's/@''GNULIB_ISFINITE''@/$(GNULIB_ISFINITE)/g' \ -e 's/@''GNULIB_ISINF''@/$(GNULIB_ISINF)/g' \ -e 's/@''GNULIB_ISNAN''@/$(GNULIB_ISNAN)/g' \ @@ -150,6 +151,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''HAVE_FREXPF''@|$(HAVE_FREXPF)|g' \ -e 's|@''HAVE_HYPOTF''@|$(HAVE_HYPOTF)|g' \ -e 's|@''HAVE_HYPOTL''@|$(HAVE_HYPOTL)|g' \ + -e 's|@''HAVE_ILOGB''@|$(HAVE_ILOGB)|g' \ -e 's|@''HAVE_ISNANF''@|$(HAVE_ISNANF)|g' \ -e 's|@''HAVE_ISNAND''@|$(HAVE_ISNAND)|g' \ -e 's|@''HAVE_ISNANL''@|$(HAVE_ISNANL)|g' \ @@ -241,6 +243,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''REPLACE_HYPOT''@|$(REPLACE_HYPOT)|g' \ -e 's|@''REPLACE_HYPOTF''@|$(REPLACE_HYPOTF)|g' \ -e 's|@''REPLACE_HYPOTL''@|$(REPLACE_HYPOTL)|g' \ + -e 's|@''REPLACE_ILOGB''@|$(REPLACE_ILOGB)|g' \ -e 's|@''REPLACE_ISFINITE''@|$(REPLACE_ISFINITE)|g' \ -e 's|@''REPLACE_ISINF''@|$(REPLACE_ISINF)|g' \ -e 's|@''REPLACE_ISNAN''@|$(REPLACE_ISNAN)|g' \ diff --git a/tests/test-math-c++.cc b/tests/test-math-c++.cc index 2c616b36f..7d1cc23f4 100644 --- a/tests/test-math-c++.cc +++ b/tests/test-math-c++.cc @@ -194,6 +194,10 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::hypotl, long double, (long double, long double)); #endif +#if GNULIB_TEST_ILOGB +SIGNATURE_CHECK (GNULIB_NAMESPACE::ilogb, int, (double)); +#endif + //SIGNATURE_CHECK (GNULIB_NAMESPACE::j0, double, (double)); //SIGNATURE_CHECK (GNULIB_NAMESPACE::j1, double, (double)); -- 2.11.0