From: Bruno Haible Date: Mon, 27 Feb 2012 11:28:29 +0000 (+0100) Subject: fmod-ieee: Work around test failures on OSF/1, mingw. X-Git-Tag: v0.1~1040 X-Git-Url: http://erislabs.net/gitweb/?a=commitdiff_plain;h=31bd9abc724408136434f6a6182c19323aba6b9e;p=gnulib.git fmod-ieee: Work around test failures on OSF/1, mingw. * m4/fmod-ieee.m4: New file. * m4/fmod.m4 (gl_FUNC_FMOD): If gl_FUNC_FMOD_IEEE is present, test whether fmod works with zero arguments. Replace it if not. * lib/math.in.h (fmod): New declaration. * lib/fmod.c: New file. * m4/math_h.m4 (gl_MATH_H): Test whether fmod is declared. (gl_MATH_H_DEFAULTS): Initialize GNULIB_FMOD, REPLACE_FMOD. * modules/math (Makefile.am): Substitute GNULIB_FMOD, REPLACE_FMOD. * modules/fmod (Files): Add lib/fmod.c. (Depends-on): Add math, isinf, trunc, fma. (configure.ac): Arrange to compile lib/fmod.c if needed. * modules/fmod-ieee (Files): Add m4/fmod-ieee.m4, m4/minus-zero.m4, m4/signbit.m4. (configure.ac): Invoke gl_FUNC_FMOD_IEEE. * tests/test-math-c++.cc: Check the declaration of fmod. * doc/posix-functions/fmod.texi: Mention the fmod-ieee module. --- diff --git a/ChangeLog b/ChangeLog index 37d52ed1a..f67a5608e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,23 @@ 2012-02-27 Bruno Haible + fmod-ieee: Work around test failures on OSF/1, mingw. + * m4/fmod-ieee.m4: New file. + * m4/fmod.m4 (gl_FUNC_FMOD): If gl_FUNC_FMOD_IEEE is present, test + whether fmod works with zero arguments. Replace it if not. + * lib/math.in.h (fmod): New declaration. + * lib/fmod.c: New file. + * m4/math_h.m4 (gl_MATH_H): Test whether fmod is declared. + (gl_MATH_H_DEFAULTS): Initialize GNULIB_FMOD, REPLACE_FMOD. + * modules/math (Makefile.am): Substitute GNULIB_FMOD, REPLACE_FMOD. + * modules/fmod (Files): Add lib/fmod.c. + (Depends-on): Add math, isinf, trunc, fma. + (configure.ac): Arrange to compile lib/fmod.c if needed. + * modules/fmod-ieee (Files): Add m4/fmod-ieee.m4, m4/minus-zero.m4, + m4/signbit.m4. + (configure.ac): Invoke gl_FUNC_FMOD_IEEE. + * tests/test-math-c++.cc: Check the declaration of fmod. + * doc/posix-functions/fmod.texi: Mention the fmod-ieee module. + fmodl-ieee: Fix test failures. * lib/fmodl.c (fmodl): Treat Inf specially. * modules/fmodl (Depends-on): Add isinf. diff --git a/doc/posix-functions/fmod.texi b/doc/posix-functions/fmod.texi index 4994762c9..0a5bbcbf3 100644 --- a/doc/posix-functions/fmod.texi +++ b/doc/posix-functions/fmod.texi @@ -4,12 +4,23 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/fmod.html} -Gnulib module: fmod +Gnulib module: fmod or fmod-ieee -Portability problems fixed by Gnulib: +Portability problems fixed by either Gnulib module @code{fmod} or @code{fmod-ieee}: @itemize @end itemize +Portability problems fixed by Gnulib module @code{fmod-ieee}: +@itemize +@item +This function has problems when the second argument is zero on some platforms: +OSF/1 5.1. +@item +This function has problems when the first argument is minus zero on some +platforms: +mingw, MSVC 9. +@end itemize + Portability problems not fixed by Gnulib: @itemize @end itemize diff --git a/lib/fmod.c b/lib/fmod.c new file mode 100644 index 000000000..9b5673eb7 --- /dev/null +++ b/lib/fmod.c @@ -0,0 +1,72 @@ +/* Remainder. + 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 + +double +fmod (double x, double y) +{ + if (isinf (y)) + return x; + else + { + double q = - trunc (x / y); + double r = fma (q, y, x); /* = x + q * y, computed in one step */ + /* Correct possible rounding errors in the quotient x / y. */ + if (y >= 0) + { + if (x >= 0) + { + /* Expect 0 <= r < y. */ + if (r < 0) + q += 1, r = fma (q, y, x); + else if (r >= y) + q -= 1, r = fma (q, y, x); + } + else + { + /* Expect - y < r <= 0. */ + if (r > 0) + q -= 1, r = fma (q, y, x); + else if (r <= - y) + q += 1, r = fma (q, y, x); + } + } + else + { + if (x >= 0) + { + /* Expect 0 <= r < - y. */ + if (r < 0) + q -= 1, r = fma (q, y, x); + else if (r >= - y) + q += 1, r = fma (q, y, x); + } + else + { + /* Expect y < r <= 0. */ + if (r > 0) + q += 1, r = fma (q, y, x); + else if (r <= y) + q -= 1, r = fma (q, y, x); + } + } + return r; + } +} diff --git a/lib/math.in.h b/lib/math.in.h index 721ddf500..abbfc6291 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -629,6 +629,26 @@ _GL_WARN_ON_USE (fmodf, "fmodf is unportable - " # endif #endif +#if @GNULIB_FMOD@ +# if @REPLACE_FMOD@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef fmod +# define fmod rpl_fmod +# endif +_GL_FUNCDECL_RPL (fmod, double, (double x, double y)); +_GL_CXXALIAS_RPL (fmod, double, (double x, double y)); +# else +_GL_CXXALIAS_SYS (fmod, double, (double x, double y)); +# endif +_GL_CXXALIASWARN (fmod); +#elif defined GNULIB_POSIXCHECK +# undef fmod +# if HAVE_RAW_DECL_FMOD +_GL_WARN_ON_USE (fmod, "fmod has portability problems - " + "use gnulib module fmod for portability"); +# endif +#endif + #if @GNULIB_FMODL@ # if @REPLACE_FMODL@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) diff --git a/m4/fmod-ieee.m4 b/m4/fmod-ieee.m4 new file mode 100644 index 000000000..61eef6947 --- /dev/null +++ b/m4/fmod-ieee.m4 @@ -0,0 +1,15 @@ +# fmod-ieee.m4 serial 1 +dnl Copyright (C) 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. + +dnl This macro is in a separate file (not in fmod.m4 and not inlined in the +dnl module description), so that gl_FUNC_FMOD can test whether 'aclocal' has +dnl found uses of this macro. + +AC_DEFUN([gl_FUNC_FMOD_IEEE], +[ + m4_divert_text([INIT_PREPARE], [gl_fmod_required=ieee]) + AC_REQUIRE([gl_FUNC_FMOD]) +]) diff --git a/m4/fmod.m4 b/m4/fmod.m4 index ff1be8313..26b1c7260 100644 --- a/m4/fmod.m4 +++ b/m4/fmod.m4 @@ -1,4 +1,4 @@ -# fmod.m4 serial 1 +# fmod.m4 serial 2 dnl Copyright (C) 2011-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, @@ -6,6 +6,80 @@ dnl with or without modifications, as long as this notice is preserved. AC_DEFUN([gl_FUNC_FMOD], [ + m4_divert_text([DEFAULTS], [gl_fmod_required=plain]) + AC_REQUIRE([gl_MATH_H_DEFAULTS]) + dnl Determine FMOD_LIBM. gl_COMMON_DOUBLE_MATHFUNC([fmod]) + + m4_ifdef([gl_FUNC_FMOD_IEEE], [ + if test $gl_fmod_required = ieee && test $REPLACE_FMOD = 0; then + AC_CACHE_CHECK([whether fmod works according to ISO C 99 with IEC 60559], + [gl_cv_func_fmod_ieee], + [ + save_LIBS="$LIBS" + LIBS="$LIBS $FMOD_LIBM" + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#ifndef __NO_MATH_INLINES +# define __NO_MATH_INLINES 1 /* for glibc */ +#endif +#include +]gl_DOUBLE_MINUS_ZERO_CODE[ +]gl_DOUBLE_SIGNBIT_CODE[ +/* Compare two numbers with ==. + This is a separate function because IRIX 6.5 "cc -O" miscompiles an + 'x == x' test. */ +static int +numeric_equal (double x, double y) +{ + return x == y; +} +static double dummy (double x, double y) { return 0; } +int main (int argc, char *argv[]) +{ + double (*my_fmod) (double, double) = argc ? fmod : dummy; + int result = 0; + double i; + double f; + /* Test fmod(...,0.0). + This test fails on OSF/1 5.1. */ + f = my_fmod (2.0, 0.0); + if (numeric_equal (f, f)) + result |= 1; + /* Test fmod(-0.0,...). + This test fails on native Windows. */ + f = my_fmod (minus_zerod, 2.0); + if (!(f == 0.0) || (signbitd (minus_zerod) && !signbitd (f))) + result |= 2; + return result; +} + ]])], + [gl_cv_func_fmod_ieee=yes], + [gl_cv_func_fmod_ieee=no], + [gl_cv_func_fmod_ieee="guessing no"]) + LIBS="$save_LIBS" + ]) + case "$gl_cv_func_fmod_ieee" in + *yes) ;; + *) REPLACE_FMOD=1 ;; + esac + fi + ]) + if test $REPLACE_FMOD = 1; then + dnl Find libraries needed to link lib/fmod.c. + AC_REQUIRE([gl_FUNC_TRUNC]) + AC_REQUIRE([gl_FUNC_FMA]) + FMOD_LIBM= + dnl Append $TRUNC_LIBM to FMOD_LIBM, avoiding gratuitous duplicates. + case " $FMOD_LIBM " in + *" $TRUNC_LIBM "*) ;; + *) FMOD_LIBM="$FMOD_LIBM $TRUNC_LIBM" ;; + esac + dnl Append $FMA_LIBM to FMOD_LIBM, avoiding gratuitous duplicates. + case " $FMOD_LIBM " in + *" $FMA_LIBM "*) ;; + *) FMOD_LIBM="$FMOD_LIBM $FMA_LIBM" ;; + esac + fi ]) diff --git a/m4/math_h.m4 b/m4/math_h.m4 index 5eb83efca..81c9da951 100644 --- a/m4/math_h.m4 +++ b/m4/math_h.m4 @@ -1,4 +1,4 @@ -# math_h.m4 serial 66 +# math_h.m4 serial 67 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, @@ -41,7 +41,8 @@ AC_DEFUN([gl_MATH_H], gl_WARN_ON_USE_PREPARE([[#include ]], [acosf acosl asinf asinl atanf atanl ceilf ceill copysign copysignf copysignl cosf cosl coshf - expf expl fabsf fabsl floorf floorl fma fmaf fmal fmodf fmodl frexpf frexpl + expf expl fabsf fabsl floorf floorl fma fmaf fmal + fmod fmodf fmodl frexpf frexpl ldexpf ldexpl logb logf logl log10f log10l modf modff modfl powf remainder remainderf remainderl rint rintf rintl round roundf roundl sinf sinl sinhf sqrtf sqrtl @@ -85,6 +86,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], GNULIB_FMA=0; AC_SUBST([GNULIB_FMA]) GNULIB_FMAF=0; AC_SUBST([GNULIB_FMAF]) GNULIB_FMAL=0; AC_SUBST([GNULIB_FMAL]) + GNULIB_FMOD=0; AC_SUBST([GNULIB_FMOD]) GNULIB_FMODF=0; AC_SUBST([GNULIB_FMODF]) GNULIB_FMODL=0; AC_SUBST([GNULIB_FMODL]) GNULIB_FREXPF=0; AC_SUBST([GNULIB_FREXPF]) @@ -211,6 +213,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS], REPLACE_FMA=0; AC_SUBST([REPLACE_FMA]) REPLACE_FMAF=0; AC_SUBST([REPLACE_FMAF]) REPLACE_FMAL=0; AC_SUBST([REPLACE_FMAL]) + REPLACE_FMOD=0; AC_SUBST([REPLACE_FMOD]) REPLACE_FMODL=0; AC_SUBST([REPLACE_FMODL]) REPLACE_FREXPF=0; AC_SUBST([REPLACE_FREXPF]) REPLACE_FREXP=0; AC_SUBST([REPLACE_FREXP]) diff --git a/modules/fmod b/modules/fmod index a8659c8b8..e68db4f99 100644 --- a/modules/fmod +++ b/modules/fmod @@ -2,13 +2,22 @@ Description: fmod() function: floating-point remainder function. Files: +lib/fmod.c m4/fmod.m4 m4/mathfunc.m4 Depends-on: +math +isinf [test $REPLACE_FMOD = 1] +trunc [test $REPLACE_FMOD = 1] +fma [test $REPLACE_FMOD = 1] configure.ac: gl_FUNC_FMOD +if test $REPLACE_FMOD = 1; then + AC_LIBOBJ([fmod]) +fi +gl_MATH_MODULE_INDICATOR([fmod]) Makefile.am: diff --git a/modules/fmod-ieee b/modules/fmod-ieee index 721dc9779..fb9192808 100644 --- a/modules/fmod-ieee +++ b/modules/fmod-ieee @@ -2,12 +2,16 @@ Description: fmod() function according to ISO C 99 with IEC 60559. Files: +m4/fmod-ieee.m4 +m4/minus-zero.m4 +m4/signbit.m4 Depends-on: fmod fpieee configure.ac: +gl_FUNC_FMOD_IEEE Makefile.am: diff --git a/modules/math b/modules/math index 189cc80e7..8dd062530 100644 --- a/modules/math +++ b/modules/math @@ -54,6 +54,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's/@''GNULIB_FMA''@/$(GNULIB_FMA)/g' \ -e 's/@''GNULIB_FMAF''@/$(GNULIB_FMAF)/g' \ -e 's/@''GNULIB_FMAL''@/$(GNULIB_FMAL)/g' \ + -e 's/@''GNULIB_FMOD''@/$(GNULIB_FMOD)/g' \ -e 's/@''GNULIB_FMODF''@/$(GNULIB_FMODF)/g' \ -e 's/@''GNULIB_FMODL''@/$(GNULIB_FMODL)/g' \ -e 's/@''GNULIB_FREXPF''@/$(GNULIB_FREXPF)/g' \ @@ -181,6 +182,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''REPLACE_FMA''@|$(REPLACE_FMA)|g' \ -e 's|@''REPLACE_FMAF''@|$(REPLACE_FMAF)|g' \ -e 's|@''REPLACE_FMAL''@|$(REPLACE_FMAL)|g' \ + -e 's|@''REPLACE_FMOD''@|$(REPLACE_FMOD)|g' \ -e 's|@''REPLACE_FMODL''@|$(REPLACE_FMODL)|g' \ -e 's|@''REPLACE_FREXPF''@|$(REPLACE_FREXPF)|g' \ -e 's|@''REPLACE_FREXP''@|$(REPLACE_FREXP)|g' \ diff --git a/tests/test-math-c++.cc b/tests/test-math-c++.cc index 241ae09db..b6534f026 100644 --- a/tests/test-math-c++.cc +++ b/tests/test-math-c++.cc @@ -137,7 +137,9 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::floorl, long double, (long double)); #if GNULIB_TEST_FMODF SIGNATURE_CHECK (GNULIB_NAMESPACE::fmodf, float, (float, float)); #endif -//SIGNATURE_CHECK (GNULIB_NAMESPACE::fmod, double, (double, double)); +#if GNULIB_TEST_FMOD +SIGNATURE_CHECK (GNULIB_NAMESPACE::fmod, double, (double, double)); +#endif #if GNULIB_TEST_FMODL SIGNATURE_CHECK (GNULIB_NAMESPACE::fmodl, long double, (long double, long double));