From 624e3c286e69a92e1610b28020c966c84f61b531 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 9 Oct 2011 18:42:07 +0200 Subject: rint: Support for MSVC. * lib/math.in.h (rint): New declaration. * lib/rint.c: New file. * m4/rint.m4: New file. * m4/math_h.m4 (gl_MATH_H): Test whether rint is declared. (gl_MATH_H_DEFAULTS): Initialize GNULIB_RINT, HAVE_RINT. * modules/math (Makefile.am): Substitute GNULIB_RINT, HAVE_RINT. * modules/rint (Description): Fix. (Files): Add lib/rint.c, m4/rint.m4. (Depends-on): Add math. (configure.ac): Invoke gl_FUNC_RINT, AC_LIBOBJ, gl_MATH_MODULE_INDICATOR. * tests/test-math-c++.cc: Check the declaration of rint. * modules/math-c++-tests (Makefile.am): Link test-math-c++ against $(RINT_LIBM). Needed on IRIX 6.5 with cc. * doc/posix-functions/rint.texi: Mention the replacement provided by the module. --- ChangeLog | 18 +++++++ doc/posix-functions/rint.texi | 6 +-- lib/math.in.h | 15 ++++++ lib/rint.c | 110 ++++++++++++++++++++++++++++++++++++++++++ m4/math_h.m4 | 6 ++- m4/rint.m4 | 17 +++++++ modules/math | 2 + modules/math-c++-tests | 3 +- modules/rint | 11 ++++- tests/test-math-c++.cc | 4 +- 10 files changed, 183 insertions(+), 9 deletions(-) create mode 100644 lib/rint.c create mode 100644 m4/rint.m4 diff --git a/ChangeLog b/ChangeLog index f3c83b1d39..449994988f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,23 @@ 2011-10-09 Bruno Haible + rint: Support for MSVC. + * lib/math.in.h (rint): New declaration. + * lib/rint.c: New file. + * m4/rint.m4: New file. + * m4/math_h.m4 (gl_MATH_H): Test whether rint is declared. + (gl_MATH_H_DEFAULTS): Initialize GNULIB_RINT, HAVE_RINT. + * modules/math (Makefile.am): Substitute GNULIB_RINT, HAVE_RINT. + * modules/rint (Description): Fix. + (Files): Add lib/rint.c, m4/rint.m4. + (Depends-on): Add math. + (configure.ac): Invoke gl_FUNC_RINT, AC_LIBOBJ, + gl_MATH_MODULE_INDICATOR. + * tests/test-math-c++.cc: Check the declaration of rint. + * modules/math-c++-tests (Makefile.am): Link test-math-c++ against + $(RINT_LIBM). Needed on IRIX 6.5 with cc. + * doc/posix-functions/rint.texi: Mention the replacement provided by + the module. + rint tests: More tests. * tests/test-rint.c: Include , , isnand-nolibm.h, minus-zero.h, infinity.h, nan.h. diff --git a/doc/posix-functions/rint.texi b/doc/posix-functions/rint.texi index 271b9f82e7..996895c06c 100644 --- a/doc/posix-functions/rint.texi +++ b/doc/posix-functions/rint.texi @@ -8,11 +8,11 @@ Gnulib module: rint Portability problems fixed by Gnulib: @itemize +@item +This function is missing on some platforms: +MSVC 9. @end itemize Portability problems not fixed by Gnulib: @itemize -@item -This function is missing on some platforms: -MSVC 9. @end itemize diff --git a/lib/math.in.h b/lib/math.in.h index cc8060e24b..7269345b7f 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -712,6 +712,21 @@ _GL_WARN_ON_USE (powf, "powf is unportable - " #endif +#if @GNULIB_RINT@ +# if !@HAVE_RINT@ +_GL_FUNCDECL_SYS (rint, double, (double x)); +# endif +_GL_CXXALIAS_SYS (rint, double, (double x)); +_GL_CXXALIASWARN (rint); +#elif defined GNULIB_POSIXCHECK +# undef rint +# if HAVE_RAW_DECL_RINT +_GL_WARN_ON_USE (rint, "rint is unportable - " + "use gnulib module rint for portability"); +# endif +#endif + + #if @GNULIB_ROUNDF@ # if @REPLACE_ROUNDF@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) diff --git a/lib/rint.c b/lib/rint.c new file mode 100644 index 0000000000..4ba3fe5547 --- /dev/null +++ b/lib/rint.c @@ -0,0 +1,110 @@ +/* Round according to the current rounding mode. + Copyright (C) 2007, 2010-2011 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. */ + +#include + +/* Specification. */ +#include + +#include +#include + +#undef MIN + +#ifdef USE_LONG_DOUBLE +# define RINT rintl +# define DOUBLE long double +# define MANT_DIG LDBL_MANT_DIG +# define MIN LDBL_MIN +# define L_(literal) literal##L +#elif ! defined USE_FLOAT +# define RINT rint +# define DOUBLE double +# define MANT_DIG DBL_MANT_DIG +# define MIN DBL_MIN +# define L_(literal) literal +#else /* defined USE_FLOAT */ +# define RINT rintf +# define DOUBLE float +# define MANT_DIG FLT_MANT_DIG +# define MIN FLT_MIN +# define L_(literal) literal##f +#endif + +/* -0.0. See minus-zero.h. */ +#if defined __hpux || defined __sgi || defined __ICC +# define MINUS_ZERO (-MIN * MIN) +#else +# define MINUS_ZERO L_(-0.0) +#endif + +DOUBLE +RINT (DOUBLE x) +{ + /* 2^(MANT_DIG-1). */ + static const DOUBLE TWO_MANT_DIG = + /* Assume MANT_DIG <= 5 * 31. + Use the identity + 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)); + + /* The use of 'volatile' guarantees that excess precision bits are dropped at + each addition step and before the following comparison at the caller's + site. It is necessary on x86 systems where double-floats are not IEEE + 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 z = x; + + /* Consider the current rounding mode, cf. + . + This implementation supports only rounds-to-nearest. */ + if (FLT_ROUNDS != 1) + abort (); + + if (z > L_(0.0)) + { + /* Avoid rounding error for x = 0.5 - 2^(-MANT_DIG-1). */ + if (z < L_(0.5)) + z = L_(0.0); + /* Avoid rounding errors for values near 2^k, where k >= MANT_DIG-1. */ + else if (z < TWO_MANT_DIG) + { + /* Round to the next integer. */ + z += TWO_MANT_DIG; + z -= TWO_MANT_DIG; + } + } + else if (z < L_(0.0)) + { + /* Avoid rounding error for x = -(0.5 - 2^(-MANT_DIG-1)). */ + if (z > - L_(0.5)) + z = MINUS_ZERO; + /* Avoid rounding errors for values near -2^k, where k >= MANT_DIG-1. */ + else if (z > -TWO_MANT_DIG) + { + /* Round to the next integer. */ + z -= TWO_MANT_DIG; + z += TWO_MANT_DIG; + } + } + return z; +} diff --git a/m4/math_h.m4 b/m4/math_h.m4 index bcc6a3f96e..c3a27e0a7b 100644 --- a/m4/math_h.m4 +++ b/m4/math_h.m4 @@ -1,4 +1,4 @@ -# math_h.m4 serial 50 +# math_h.m4 serial 51 dnl Copyright (C) 2007-2011 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -43,7 +43,7 @@ AC_DEFUN([gl_MATH_H], ceilf ceill copysign copysignf copysignl cosf cosl coshf expf expl fabsf floorf floorl fmodf frexpf frexpl ldexpf ldexpl logb logf logl log10f modff powf - round roundf roundl sinf sinl sinhf sqrtf sqrtl + rint round roundf roundl sinf sinl sinhf sqrtf sqrtl tanf tanl tanhf trunc truncf truncl]) ]) @@ -98,6 +98,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], GNULIB_LOG10F=0; AC_SUBST([GNULIB_LOG10F]) GNULIB_MODFF=0; AC_SUBST([GNULIB_MODFF]) GNULIB_POWF=0; AC_SUBST([GNULIB_POWF]) + GNULIB_RINT=0; AC_SUBST([GNULIB_RINT]) GNULIB_ROUND=0; AC_SUBST([GNULIB_ROUND]) GNULIB_ROUNDF=0; AC_SUBST([GNULIB_ROUNDF]) GNULIB_ROUNDL=0; AC_SUBST([GNULIB_ROUNDL]) @@ -141,6 +142,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], HAVE_LOG10F=1; AC_SUBST([HAVE_LOG10F]) HAVE_MODFF=1; AC_SUBST([HAVE_MODFF]) HAVE_POWF=1; AC_SUBST([HAVE_POWF]) + HAVE_RINT=1; AC_SUBST([HAVE_RINT]) HAVE_SINF=1; AC_SUBST([HAVE_SINF]) HAVE_SINL=1; AC_SUBST([HAVE_SINL]) HAVE_SINHF=1; AC_SUBST([HAVE_SINHF]) diff --git a/m4/rint.m4 b/m4/rint.m4 new file mode 100644 index 0000000000..9d7335d28a --- /dev/null +++ b/m4/rint.m4 @@ -0,0 +1,17 @@ +# rint.m4 serial 1 +dnl Copyright (C) 2011 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_RINT], +[ + dnl Determine RINT_LIBM. + gl_MATHFUNC([rint], [double], [(double)]) + if test $gl_cv_func_rint_no_libm = no \ + && test $gl_cv_func_rint_in_libm = no; then + HAVE_RINT=0 + RINT_LIBM= + fi + AC_SUBST([RINT_LIBM]) +]) diff --git a/modules/math b/modules/math index 0e0f4eae29..57d5798860 100644 --- a/modules/math +++ b/modules/math @@ -68,6 +68,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's/@''GNULIB_LOG10F''@/$(GNULIB_LOG10F)/g' \ -e 's/@''GNULIB_MODFF''@/$(GNULIB_MODFF)/g' \ -e 's/@''GNULIB_POWF''@/$(GNULIB_POWF)/g' \ + -e 's/@''GNULIB_RINT''@/$(GNULIB_RINT)/g' \ -e 's/@''GNULIB_ROUND''@/$(GNULIB_ROUND)/g' \ -e 's/@''GNULIB_ROUNDF''@/$(GNULIB_ROUNDF)/g' \ -e 's/@''GNULIB_ROUNDL''@/$(GNULIB_ROUNDL)/g' \ @@ -111,6 +112,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''HAVE_LOG10F''@|$(HAVE_LOG10F)|g' \ -e 's|@''HAVE_MODFF''@|$(HAVE_MODFF)|g' \ -e 's|@''HAVE_POWF''@|$(HAVE_POWF)|g' \ + -e 's|@''HAVE_RINT''@|$(HAVE_RINT)|g' \ -e 's|@''HAVE_SINF''@|$(HAVE_SINF)|g' \ -e 's|@''HAVE_SINL''@|$(HAVE_SINL)|g' \ -e 's|@''HAVE_SINHF''@|$(HAVE_SINHF)|g' \ diff --git a/modules/math-c++-tests b/modules/math-c++-tests index 6e2d003437..35f37b8420 100644 --- a/modules/math-c++-tests +++ b/modules/math-c++-tests @@ -16,5 +16,6 @@ if ANSICXX TESTS += test-math-c++ check_PROGRAMS += test-math-c++ test_math_c___SOURCES = test-math-c++.cc test-math-c++2.cc -test_math_c___LDADD = $(LDADD) $(COPYSIGNL_LIBM) +# These link dependencies are needed on IRIX 6.5 with cc. +test_math_c___LDADD = $(LDADD) $(COPYSIGNL_LIBM) $(RINT_LIBM) endif diff --git a/modules/rint b/modules/rint index 276c9263f9..08cdc4ca47 100644 --- a/modules/rint +++ b/modules/rint @@ -1,13 +1,20 @@ Description: -rint() function: round to nearest integer. +rint() function: round according to the current rounding mode. Files: +lib/rint.c +m4/rint.m4 m4/mathfunc.m4 Depends-on: +math configure.ac: -gl_MATHFUNC([rint], [double], [(double)]) +gl_FUNC_RINT +if test $HAVE_RINT = 0; then + AC_LIBOBJ([rint]) +fi +gl_MATH_MODULE_INDICATOR([rint]) Makefile.am: diff --git a/tests/test-math-c++.cc b/tests/test-math-c++.cc index 371249246e..95be24f605 100644 --- a/tests/test-math-c++.cc +++ b/tests/test-math-c++.cc @@ -104,7 +104,9 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::powf, float, (float, float)); #endif //SIGNATURE_CHECK (GNULIB_NAMESPACE::pow, double, (double, double)); //SIGNATURE_CHECK (GNULIB_NAMESPACE::remainder, double, (double, double)); -//SIGNATURE_CHECK (GNULIB_NAMESPACE::rint, double, (double)); +#if GNULIB_TEST_RINT +SIGNATURE_CHECK (GNULIB_NAMESPACE::rint, double, (double)); +#endif #if GNULIB_TEST_SINF SIGNATURE_CHECK (GNULIB_NAMESPACE::sinf, float, (float)); #endif -- cgit v1.2.1