# HG changeset patch # User Bruno Haible # Date 1191539197 -7200 # Node ID 79e67a783774e5faf7f5ce26bf3329ebf2e65d62 # Parent afba4e078ebc762ab75d75934ab274b32f3af36a New module 'truncf'. diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2007-10-04 Bruno Haible + + * modules/truncf: New file. + * lib/trunc.c: Make paramerizable through USE_* macros. + * lib/truncf.c: New file. + * m4/truncf.m4: New file. + * lib/math.in.h (truncf): New declaration. + * m4/math_h.m4 (gl_MATH_H_DEFAULTS): Initialize GNULIB_TRUNCF and + HAVE_DECL_TRUNCF. + * modules/math (Makefile.am): Substitute also GNULIB_TRUNCF and + HAVE_DECL_TRUNCF. + * doc/functions/truncf.texi: Mention the 'truncf' module. + 2007-10-03 Bruno Haible * gnulib-tool (func_get_automake_snippet): Synthesize an EXTRA_DIST diff --git a/doc/functions/truncf.texi b/doc/functions/truncf.texi --- a/doc/functions/truncf.texi +++ b/doc/functions/truncf.texi @@ -4,15 +4,15 @@ POSIX specification: @url{http://www.opengroup.org/susv3xsh/truncf.html} -Gnulib module: --- +Gnulib module: truncf Portability problems fixed by Gnulib: @itemize -@end itemize - -Portability problems not fixed by Gnulib: -@itemize @item This function is missing on some platforms: FreeBSD 5.2.1, NetBSD 3.0, OpenBSD 3.8, AIX 5.1, HP-UX 11, Solaris 9, Interix 3.5. @end itemize + +Portability problems not fixed by Gnulib: +@itemize +@end itemize diff --git a/lib/math.in.h b/lib/math.in.h --- a/lib/math.in.h +++ b/lib/math.in.h @@ -65,6 +65,7 @@ acosl (x)) #endif + #if @GNULIB_MATHL@ || !@HAVE_DECL_ASINL@ extern long double asinl (long double x); #endif @@ -76,6 +77,7 @@ asinl (x)) #endif + #if @GNULIB_MATHL@ || !@HAVE_DECL_ATANL@ extern long double atanl (long double x); #endif @@ -87,6 +89,7 @@ atanl (x)) #endif + #if @GNULIB_MATHL@ || !@HAVE_DECL_CEILL@ extern long double ceill (long double x); #endif @@ -98,6 +101,7 @@ ceill (x)) #endif + #if @GNULIB_MATHL@ || !@HAVE_DECL_COSL@ extern long double cosl (long double x); #endif @@ -109,6 +113,7 @@ cosl (x)) #endif + #if @GNULIB_MATHL@ || !@HAVE_DECL_EXPL@ extern long double expl (long double x); #endif @@ -120,6 +125,7 @@ expl (x)) #endif + #if @GNULIB_MATHL@ || !@HAVE_DECL_FLOORL@ extern long double floorl (long double x); #endif @@ -131,6 +137,7 @@ floorl (x)) #endif + /* Write x as x = mantissa * 2^exp where @@ -152,6 +159,7 @@ frexpl (x, e)) #endif + /* Return x * 2^exp. */ #if @GNULIB_LDEXPL@ && @REPLACE_LDEXPL@ # define ldexpl rpl_ldexpl @@ -167,6 +175,7 @@ ldexpl (x, e)) #endif + #if @GNULIB_MATHL@ || !@HAVE_DECL_LOGL@ extern long double logl (long double x); #endif @@ -178,6 +187,7 @@ logl (x)) #endif + #if @GNULIB_MATHL@ || !@HAVE_DECL_SINL@ extern long double sinl (long double x); #endif @@ -189,6 +199,7 @@ sinl (x)) #endif + #if @GNULIB_MATHL@ || !@HAVE_DECL_SQRTL@ extern long double sqrtl (long double x); #endif @@ -200,6 +211,7 @@ sqrtl (x)) #endif + #if @GNULIB_MATHL@ || !@HAVE_DECL_TANL@ extern long double tanl (long double x); #endif @@ -211,6 +223,20 @@ tanl (x)) #endif + +#if @GNULIB_TRUNCF@ +# if !@HAVE_DECL_TRUNCF@ +# define truncf rpl_truncf +extern float truncf (float x); +# endif +#elif defined GNULIB_POSIXCHECK +# undef truncf +# define truncf(x) \ + (GL_LINK_WARNING ("truncf is unportable - " \ + "use gnulib module truncf for portability"), \ + truncf (x)) +#endif + #if @GNULIB_TRUNC@ # if !@HAVE_DECL_TRUNC@ # define trunc rpl_trunc diff --git a/lib/trunc.c b/lib/trunc.c --- a/lib/trunc.c +++ b/lib/trunc.c @@ -24,18 +24,36 @@ #include -/* 2^(DBL_MANT_DIG-1). */ +#ifdef USE_LONG_DOUBLE +# define FUNC truncl +# define DOUBLE long double +# define MANT_DIG LDBL_MANT_DIG +# define L_(literal) literal##L +#elif ! defined USE_FLOAT +# define FUNC trunc +# define DOUBLE double +# define MANT_DIG DBL_MANT_DIG +# define L_(literal) literal +#else /* defined USE_FLOAT */ +# define FUNC truncf +# define DOUBLE float +# define MANT_DIG FLT_MANT_DIG +# define L_(literal) literal##f +#endif + +/* 2^(MANT_DIG-1). */ static const double TWO_MANT_DIG = - /* Assume DBL_MANT_DIG <= 4 * 31. + /* Assume MANT_DIG <= 5 * 31. Use the identity - n = floor(n/4) + floor((n+1)/4) + floor((n+2)/4) + floor((n+3)/4). */ - (double) (1U << ((DBL_MANT_DIG - 1) / 4)) - * (double) (1U << ((DBL_MANT_DIG - 1 + 1) / 4)) - * (double) (1U << ((DBL_MANT_DIG - 1 + 2) / 4)) - * (double) (1U << ((DBL_MANT_DIG - 1 + 3) / 4)); + n = floor(n/5) + floor((n+1)/5) + ... + floor((n+4)/5). */ + (DOUBLE) (1U << ((MANT_DIG - 1) / 5)) + * (DOUBLE) (1U << ((MANT_DIG - 1 + 1) / 5)) + * (DOUBLE) (1U << ((MANT_DIG - 1 + 2) / 5)) + * (DOUBLE) (1U << ((MANT_DIG - 1 + 3) / 5)) + * (DOUBLE) (1U << ((MANT_DIG - 1 + 4) / 5)); -double -trunc (double x) +DOUBLE +FUNC (DOUBLE x) { /* The use of 'volatile' guarantees that excess precision bits are dropped at each addition step and before the following comparison at the caller's @@ -43,26 +61,26 @@ compliant by default, to avoid that the results become platform and compiler option dependent. 'volatile' is a portable alternative to gcc's -ffloat-store option. */ - volatile double y = x; - volatile double z = y; + volatile DOUBLE y = x; + volatile DOUBLE z = y; - if (z > 0) + if (z > L_(0.0)) { /* Round to the next integer (nearest or up or down, doesn't matter). */ z += TWO_MANT_DIG; z -= TWO_MANT_DIG; /* Enforce rounding down. */ if (z > y) - z -= 1.0; + z -= L_(1.0); } - else if (z < 0) + else if (z < L_(0.0)) { /* Round to the next integer (nearest or up or down, doesn't matter). */ z -= TWO_MANT_DIG; z += TWO_MANT_DIG; /* Enforce rounding up. */ if (z < y) - z += 1.0; + z += L_(1.0); } return z; } diff --git a/lib/truncf.c b/lib/truncf.c new file mode 100644 --- /dev/null +++ b/lib/truncf.c @@ -0,0 +1,21 @@ +/* Round towards zero. + Copyright (C) 2007 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 2, 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, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Bruno Haible , 2007. */ + +#define USE_FLOAT +#include "trunc.c" diff --git a/m4/math_h.m4 b/m4/math_h.m4 --- a/m4/math_h.m4 +++ b/m4/math_h.m4 @@ -25,6 +25,7 @@ GNULIB_MATHL=0; AC_SUBST([GNULIB_MATHL]) GNULIB_SIGNBIT=0; AC_SUBST([GNULIB_SIGNBIT]) GNULIB_TRUNC=0; AC_SUBST([GNULIB_TRUNC]) + GNULIB_TRUNCF=0; AC_SUBST([GNULIB_TRUNCF]) dnl Assume proper GNU behavior unless another module says otherwise. HAVE_DECL_ACOSL=1; AC_SUBST([HAVE_DECL_ACOSL]) HAVE_DECL_ASINL=1; AC_SUBST([HAVE_DECL_ASINL]) @@ -40,6 +41,7 @@ HAVE_DECL_SQRTL=1; AC_SUBST([HAVE_DECL_SQRTL]) HAVE_DECL_TANL=1; AC_SUBST([HAVE_DECL_TANL]) HAVE_DECL_TRUNC=1; AC_SUBST([HAVE_DECL_TRUNC]) + HAVE_DECL_TRUNCF=1; AC_SUBST([HAVE_DECL_TRUNCF]) REPLACE_FREXP=0; AC_SUBST([REPLACE_FREXP]) REPLACE_FREXPL=0; AC_SUBST([REPLACE_FREXPL]) REPLACE_LDEXPL=0; AC_SUBST([REPLACE_LDEXPL]) diff --git a/m4/truncf.m4 b/m4/truncf.m4 new file mode 100644 --- /dev/null +++ b/m4/truncf.m4 @@ -0,0 +1,48 @@ +# truncf.m4 serial 1 +dnl Copyright (C) 2007 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_TRUNCF], +[ + AC_REQUIRE([gl_MATH_H_DEFAULTS]) + dnl Persuade glibc to declare truncf(). + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + dnl Test whether truncf() is declared. + AC_CHECK_DECLS([truncf], , , [#include ]) + if test "$ac_cv_have_decl_truncf" = yes; then + dnl Test whether truncf() can be used without libm. + TRUNCF_LIBM=? + AC_TRY_LINK([ + #ifndef __NO_MATH_INLINES + # define __NO_MATH_INLINES 1 /* for glibc */ + #endif + #include + float x;], + [x = truncf(x);], + [TRUNCF_LIBM=]) + if test "$TRUNCF_LIBM" = "?"; then + save_LIBS="$LIBS" + LIBS="$LIBS -lm" + AC_TRY_LINK([ + #ifndef __NO_MATH_INLINES + # define __NO_MATH_INLINES 1 /* for glibc */ + #endif + #include + float x;], + [x = truncf(x);], + [TRUNCF_LIBM="-lm"]) + LIBS="$save_LIBS" + fi + if test "$TRUNCF_LIBM" = "?"; then + TRUNCF_LIBM= + fi + else + HAVE_DECL_TRUNCF=0 + AC_LIBOBJ([truncf]) + TRUNCF_LIBM= + fi + AC_SUBST([HAVE_DECL_TRUNCF]) + AC_SUBST([TRUNCF_LIBM]) +]) diff --git a/modules/math b/modules/math --- a/modules/math +++ b/modules/math @@ -28,6 +28,7 @@ -e 's|@''GNULIB_MATHL''@|$(GNULIB_MATHL)|g' \ -e 's|@''GNULIB_SIGNBIT''@|$(GNULIB_SIGNBIT)|g' \ -e 's|@''GNULIB_TRUNC''@|$(GNULIB_TRUNC)|g' \ + -e 's|@''GNULIB_TRUNCF''@|$(GNULIB_TRUNCF)|g' \ -e 's|@''HAVE_DECL_ACOSL''@|$(HAVE_DECL_ACOSL)|g' \ -e 's|@''HAVE_DECL_ASINL''@|$(HAVE_DECL_ASINL)|g' \ -e 's|@''HAVE_DECL_ATANL''@|$(HAVE_DECL_ATANL)|g' \ @@ -42,6 +43,7 @@ -e 's|@''HAVE_DECL_SQRTL''@|$(HAVE_DECL_SQRTL)|g' \ -e 's|@''HAVE_DECL_TANL''@|$(HAVE_DECL_TANL)|g' \ -e 's|@''HAVE_DECL_TRUNC''@|$(HAVE_DECL_TRUNC)|g' \ + -e 's|@''HAVE_DECL_TRUNCF''@|$(HAVE_DECL_TRUNCF)|g' \ -e 's|@''REPLACE_FREXP''@|$(REPLACE_FREXP)|g' \ -e 's|@''REPLACE_FREXPL''@|$(REPLACE_FREXPL)|g' \ -e 's|@''REPLACE_LDEXPL''@|$(REPLACE_LDEXPL)|g' \ diff --git a/modules/truncf b/modules/truncf new file mode 100644 --- /dev/null +++ b/modules/truncf @@ -0,0 +1,31 @@ +Description: +truncf() function: round towards zero. + +Files: +lib/truncf.c +lib/trunc.c +m4/truncf.m4 + +Depends-on: +math +extensions +float + +configure.ac: +gl_FUNC_TRUNCF +gl_MATH_MODULE_INDICATOR([truncf]) + +Makefile.am: + +Include: + + +Link: +$(TRUNCF_LIBM) + +License: +LGPL + +Maintainer: +Bruno Haible +