* 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.
2012-02-27 Bruno Haible <bruno@clisp.org>
+ 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.
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
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include <math.h>
+
+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;
+ }
+}
# 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)
--- /dev/null
+# 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])
+])
-# 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,
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 <math.h>
+]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
])
-# 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,
gl_WARN_ON_USE_PREPARE([[#include <math.h>]],
[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
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])
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])
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:
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:
-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' \
-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' \
#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));