summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog30
-rwxr-xr-xMODULES.html.sh3
-rw-r--r--doc/functions/round.texi8
-rw-r--r--doc/functions/roundf.texi8
-rw-r--r--doc/functions/roundl.texi8
-rw-r--r--lib/math.in.h42
-rw-r--r--lib/round.c154
-rw-r--r--lib/roundf.c19
-rw-r--r--lib/roundl.c19
-rw-r--r--m4/check-libm-func.m451
-rw-r--r--m4/math_h.m46
-rw-r--r--m4/round.m415
-rw-r--r--m4/roundf.m422
-rw-r--r--m4/roundl.m422
-rw-r--r--modules/math6
-rw-r--r--modules/round32
-rw-r--r--modules/round-tests21
-rw-r--r--modules/roundf32
-rw-r--r--modules/roundf-tests22
-rw-r--r--modules/roundl32
-rw-r--r--modules/roundl-tests16
-rw-r--r--tests/test-round1.c90
-rw-r--r--tests/test-round2.c108
-rw-r--r--tests/test-roundf1.c90
-rw-r--r--tests/test-roundf2.c2
-rw-r--r--tests/test-roundl.c85
26 files changed, 931 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog
index aa77450c82..c8f01a4450 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,33 @@
+2007-10-20 Ben Pfaff <blp@gnu.org>
+
+ * lib/math.in.h: Declare round, roundf, roundl if we are providing
+ implementations.
+ * m4/math_h.m4: New substitutions for round, roundf, roundl modules.
+ * lib/round.c: New file.
+ * lib/roundf.c: New file.
+ * lib/roundl.c: New file.
+ * m4/round.m4: New file.
+ * m4/roundf.m4: New file.
+ * m4/roundl.m4: New file.
+ * m4/check-libm-func-m4: New file.
+ * modules/math: Replace round, roundf, roundl related @VARS@ in
+ math.in.h.
+ * modules/round: New file.
+ * modules/round-tests: New file.
+ * modules/roundf: New file.
+ * modules/roundf-tests: New file.
+ * modules/roundl: New file.
+ * modules/roundl-tests: New file.
+ * tests/test-round1.c: New file.
+ * tests/test-round2.c: New file.
+ * tests/test-roundf1.c: New file.
+ * tests/test-roundf2.c: New file.
+ * tests/test-roundl.c: New file.
+ * doc/functions/round.texi: Mention round module.
+ * doc/functions/roundf.texi: Mention roundf module.
+ * doc/functions/roundl.texi: Mention roundl module.
+ * MODULES.html.sh: Mention new modules.
+
2007-10-20 Jim Meyering <meyering@redhat.com>
* lib/xprintf.c: Include <config.h> unconditionally.
diff --git a/MODULES.html.sh b/MODULES.html.sh
index 7934cc9749..11c4e3e3ae 100755
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -1977,6 +1977,9 @@ func_all_modules ()
func_module ldexpl
func_module math
func_module mathl
+ func_module round
+ func_module roundf
+ func_module roundl
func_module signbit
func_module trunc
func_module truncf
diff --git a/doc/functions/round.texi b/doc/functions/round.texi
index 9910e23aa5..28eb574c28 100644
--- a/doc/functions/round.texi
+++ b/doc/functions/round.texi
@@ -4,15 +4,15 @@
POSIX specification: @url{http://www.opengroup.org/susv3xsh/round.html}
-Gnulib module: ---
+Gnulib module: round
Portability problems fixed by Gnulib:
@itemize
+@item
+This function is missing on some platforms:
+FreeBSD 5.2.1, OpenBSD 3.8, AIX 5.1, IRIX 6.5, OSF/1 4.0, Solaris 9, Interix 3.5.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
-@item
-This function is missing on some platforms:
-FreeBSD 5.2.1, OpenBSD 3.8, AIX 5.1, IRIX 6.5, OSF/1 4.0, Solaris 9, Interix 3.5.
@end itemize
diff --git a/doc/functions/roundf.texi b/doc/functions/roundf.texi
index f389a64f3b..41b3a7f04c 100644
--- a/doc/functions/roundf.texi
+++ b/doc/functions/roundf.texi
@@ -4,15 +4,15 @@
POSIX specification: @url{http://www.opengroup.org/susv3xsh/roundf.html}
-Gnulib module: ---
+Gnulib module: roundf
Portability problems fixed by Gnulib:
@itemize
+@item
+This function is missing on some platforms:
+FreeBSD 5.2.1, OpenBSD 3.8, AIX 5.1, HP-UX 11, IRIX 6.5, OSF/1 4.0, Solaris 9, Interix 3.5.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
-@item
-This function is missing on some platforms:
-FreeBSD 5.2.1, OpenBSD 3.8, AIX 5.1, HP-UX 11, IRIX 6.5, OSF/1 4.0, Solaris 9, Interix 3.5.
@end itemize
diff --git a/doc/functions/roundl.texi b/doc/functions/roundl.texi
index 439a0a8550..a4eaa7d99f 100644
--- a/doc/functions/roundl.texi
+++ b/doc/functions/roundl.texi
@@ -4,15 +4,15 @@
POSIX specification: @url{http://www.opengroup.org/susv3xsh/roundl.html}
-Gnulib module: ---
+Gnulib module: roundl
Portability problems 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, IRIX 6.5, OSF/1 4.0, Solaris 9, Cygwin, Interix 3.5, BeOS.
@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, IRIX 6.5, OSF/1 4.0, Solaris 9, Cygwin, Interix 3.5, BeOS.
@end itemize
diff --git a/lib/math.in.h b/lib/math.in.h
index 93eeb9327e..c5d98f0091 100644
--- a/lib/math.in.h
+++ b/lib/math.in.h
@@ -217,6 +217,48 @@ extern long double logl (long double x);
#endif
+#if @GNULIB_ROUNDF@
+# if !@HAVE_DECL_ROUNDF@
+# define roundf rpl_roundf
+extern float roundf (float x);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef roundf
+# define roundf(x) \
+ (GL_LINK_WARNING ("roundf is unportable - " \
+ "use gnulib module roundf for portability"), \
+ roundf (x))
+#endif
+
+
+#if @GNULIB_ROUND@
+# if !@HAVE_DECL_ROUND@
+# define round rpl_round
+extern double round (double x);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef round
+# define round(x) \
+ (GL_LINK_WARNING ("round is unportable - " \
+ "use gnulib module round for portability"), \
+ round (x))
+#endif
+
+
+#if @GNULIB_ROUNDL@
+# if !@HAVE_DECL_ROUNDL@
+# define roundl rpl_roundl
+extern long double roundl (long double x);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef roundl
+# define roundl(x) \
+ (GL_LINK_WARNING ("roundl is unportable - " \
+ "use gnulib module roundl for portability"), \
+ roundl (x))
+#endif
+
+
#if @GNULIB_MATHL@ || !@HAVE_DECL_SINL@
extern long double sinl (long double x);
#endif
diff --git a/lib/round.c b/lib/round.c
new file mode 100644
index 0000000000..5758fb7c79
--- /dev/null
+++ b/lib/round.c
@@ -0,0 +1,154 @@
+/* Round toward nearest, breaking ties away from 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 Ben Pfaff <blp@gnu.org>, 2007.
+ Based heavily on code by Bruno Haible. */
+
+#include <config.h>
+
+#include <float.h>
+#include <math.h>
+
+#ifdef USE_LONG_DOUBLE
+# define ROUND roundl
+# define FLOOR floorl
+# define CEIL ceill
+# define DOUBLE long double
+# define MANT_DIG LDBL_MANT_DIG
+# define L_(literal) literal##L
+# define HAVE_FLOOR_AND_CEIL (HAVE_DECL_FLOORL && HAVE_DECL_CEILL)
+#elif ! defined USE_FLOAT
+# define ROUND round
+# define FLOOR floor
+# define CEIL ceil
+# define DOUBLE double
+# define MANT_DIG DBL_MANT_DIG
+# define L_(literal) literal
+# define HAVE_FLOOR_AND_CEIL 1
+#else /* defined USE_FLOAT */
+# define ROUND roundf
+# define FLOOR floorf
+# define CEIL ceilf
+# define DOUBLE float
+# define MANT_DIG FLT_MANT_DIG
+# define L_(literal) literal##f
+# define HAVE_FLOOR_AND_CEIL (HAVE_DECL_FLOORF && HAVE_DECL_CEILF)
+#endif
+
+/* If we're being included from test-round2[f].c, it already defined names for
+ our round implementations. Otherwise, pick the preferred implementation for
+ this machine. */
+#if !defined FLOOR_BASED_ROUND && !defined FLOOR_FREE_ROUND
+# if HAVE_FLOOR_AND_CEIL
+# define FLOOR_BASED_ROUND ROUND
+# else
+# define FLOOR_FREE_ROUND ROUND
+# endif
+#endif
+
+#ifdef FLOOR_BASED_ROUND
+/* An implementation of the C99 round function based on floor and ceil. We use
+ this when floor and ceil are available, on the assumption that they are
+ faster than the open-coded versions below. */
+DOUBLE
+FLOOR_BASED_ROUND (DOUBLE x)
+{
+ if (x >= L_(0.0))
+ {
+ DOUBLE y = FLOOR (x);
+ if (x - y >= L_(0.5))
+ y += L_(1.0);
+ return y;
+ }
+ else
+ {
+ DOUBLE y = CEIL (x);
+ if (y - x >= L_(0.5))
+ y -= L_(1.0);
+ return y;
+ }
+}
+#endif /* FLOOR_BASED_ROUND */
+
+#ifdef FLOOR_FREE_ROUND
+/* An implementation of the C99 round function without floor or ceil.
+ We use this when floor or ceil is missing. */
+DOUBLE
+FLOOR_FREE_ROUND (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 y = x;
+ volatile DOUBLE z = y;
+
+ 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)
+ {
+ /* Add 0.5 to the absolute value. */
+ y = z += L_(0.5);
+ /* 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 -= L_(1.0);
+ }
+ }
+ else 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)
+ {
+ /* Add 0.5 to the absolute value. */
+ y = z -= L_(0.5);
+ /* 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 += L_(1.0);
+ }
+ }
+ return z;
+}
+#endif /* FLOOR_FREE_ROUND */
+
diff --git a/lib/roundf.c b/lib/roundf.c
new file mode 100644
index 0000000000..8d7f94b50d
--- /dev/null
+++ b/lib/roundf.c
@@ -0,0 +1,19 @@
+/* Round toward nearest, breaking ties away from 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. */
+
+#define USE_FLOAT
+#include "round.c"
diff --git a/lib/roundl.c b/lib/roundl.c
new file mode 100644
index 0000000000..e53ac0a5d1
--- /dev/null
+++ b/lib/roundl.c
@@ -0,0 +1,19 @@
+/* Round toward nearest, breaking ties away from 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. */
+
+#define USE_LONG_DOUBLE
+#include "round.c"
diff --git a/m4/check-libm-func.m4 b/m4/check-libm-func.m4
new file mode 100644
index 0000000000..e375558aa6
--- /dev/null
+++ b/m4/check-libm-func.m4
@@ -0,0 +1,51 @@
+# check-libm.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.
+dnl
+dnl AC_CHECK_LIBM_FUNC (MATH_FUNCTION, INVOCATION,
+dnl [RUN-IF-FOUND], [RUN-IF-NOT-FOUND])
+dnl
+dnl Checks for a declaration of the given MATH_FUNCTION in <math.h>, and
+dnl substitutes HAVE_DECL_<func> accordingly. If a declaration is found,
+dnl determines the needed library (if any), assigns it to <func>_LIBM, and
+dnl executes RUN-IF-FOUND; otherwise, executes RUN-IF-NOT-FOUND.
+dnl
+dnl INVOCATION should be a C statement that invokes MATH_FUNCTION, both
+dnl using and assigning back to double variable 'x', e.g. "x = floor
+dnl (x);".
+AC_DEFUN([gl_CHECK_LIBM_FUNC],
+[
+m4_pushdef([FUNC_LIBM], m4_toupper([$1])[_LIBM])dnl
+m4_pushdef([HAVE_DECL_FUNC], HAVE_DECL_[]m4_toupper([$1]))dnl
+ AC_CHECK_DECLS([$1], , , [#include <math.h>])
+ if test "$ac_cv_have_decl_$1" = yes; then
+ save_LIBS=$LIBS
+ FUNC_LIBM=?
+ for libm in "" "-lm"; do
+ LIBS="$save_LIBS $libm"
+ AC_TRY_LINK([
+ #ifndef __NO_MATH_INLINES
+ # define __NO_MATH_INLINES 1 /* for glibc */
+ #endif
+ #include <math.h>
+ double x;],
+ [$2],
+ [FUNC_LIBM=$libm
+break])
+ done
+ LIBS=$save_LIBS
+ if test "$FUNC_LIBM" = "?"; then
+ FUNC_LIBM=
+ fi
+m4_ifvaln([$3], [$3])dnl
+ else
+ HAVE_DECL_FUNC=
+ FUNC_LIBM=
+m4_ifvaln([$4], [$4])dnl
+ fi
+ AC_SUBST(HAVE_DECL_FUNC)
+ AC_SUBST(FUNC_LIBM)
+m4_popdef([FUNC_LIBM])
+m4_popdef([HAVE_DECL_FUNC])])
diff --git a/m4/math_h.m4 b/m4/math_h.m4
index 5539d792f5..4806e08e4f 100644
--- a/m4/math_h.m4
+++ b/m4/math_h.m4
@@ -27,6 +27,9 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
GNULIB_FREXPL=0; AC_SUBST([GNULIB_FREXPL])
GNULIB_LDEXPL=0; AC_SUBST([GNULIB_LDEXPL])
GNULIB_MATHL=0; AC_SUBST([GNULIB_MATHL])
+ GNULIB_ROUND=0; AC_SUBST([GNULIB_ROUND])
+ GNULIB_ROUNDF=0; AC_SUBST([GNULIB_ROUNDF])
+ GNULIB_ROUNDL=0; AC_SUBST([GNULIB_ROUNDL])
GNULIB_SIGNBIT=0; AC_SUBST([GNULIB_SIGNBIT])
GNULIB_TRUNC=0; AC_SUBST([GNULIB_TRUNC])
GNULIB_TRUNCF=0; AC_SUBST([GNULIB_TRUNCF])
@@ -44,6 +47,9 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
HAVE_DECL_FREXPL=1; AC_SUBST([HAVE_DECL_FREXPL])
HAVE_DECL_LDEXPL=1; AC_SUBST([HAVE_DECL_LDEXPL])
HAVE_DECL_LOGL=1; AC_SUBST([HAVE_DECL_LOGL])
+ HAVE_DECL_ROUND=1; AC_SUBST([HAVE_DECL_ROUND])
+ HAVE_DECL_ROUNDF=1; AC_SUBST([HAVE_DECL_ROUNDF])
+ HAVE_DECL_ROUNDL=1; AC_SUBST([HAVE_DECL_ROUNDL])
HAVE_DECL_SINL=1; AC_SUBST([HAVE_DECL_SINL])
HAVE_DECL_SQRTL=1; AC_SUBST([HAVE_DECL_SQRTL])
HAVE_DECL_TANL=1; AC_SUBST([HAVE_DECL_TANL])
diff --git a/m4/round.m4 b/m4/round.m4
new file mode 100644
index 0000000000..edd9e8979c
--- /dev/null
+++ b/m4/round.m4
@@ -0,0 +1,15 @@
+# round.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_ROUND],
+[
+ AC_REQUIRE([gl_MATH_H_DEFAULTS])
+ dnl Persuade glibc <math.h> to declare round().
+ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+ gl_CHECK_LIBM_FUNC([round], [x = round(x);], [], [
+ AC_REQUIRE([gl_FUNC_FLOOR])
+ ROUND_LIBM=$FLOOR_LIBM
+ AC_LIBOBJ([round])])])
diff --git a/m4/roundf.m4 b/m4/roundf.m4
new file mode 100644
index 0000000000..57778a8660
--- /dev/null
+++ b/m4/roundf.m4
@@ -0,0 +1,22 @@
+# roundf.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_ROUNDF],
+[
+ AC_REQUIRE([gl_MATH_H_DEFAULTS])
+ dnl Persuade glibc <math.h> to declare roundf().
+ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+ dnl Test whether roundf() is declared.
+ gl_CHECK_LIBM_FUNC([roundf], [x = roundf(x);], [], [
+ dnl No. Are both floorf() and ceilf() available? If so then we can use
+ dnl them to implement roundf(), on the assumption that they're fast.
+ gl_CHECK_LIBM_FUNC([floorf], [x = floorf(x);], [
+ AC_CHECK_DECL([ceilf],
+ [dnl Yes. Both are declared. Link against the necessary library.
+ ROUNDF_LIBM="$FLOORF_LIBM"],
+ [: dnl No. We will use an implementation that doesn't need them.
+], [#include <math.h>
+])])])])
diff --git a/m4/roundl.m4 b/m4/roundl.m4
new file mode 100644
index 0000000000..6bec36bdc1
--- /dev/null
+++ b/m4/roundl.m4
@@ -0,0 +1,22 @@
+# roundl.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_ROUNDL],
+[
+ AC_REQUIRE([gl_MATH_H_DEFAULTS])
+ dnl Persuade glibc <math.h> to declare roundl().
+ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+ dnl Test whether roundl() is declared.
+ gl_CHECK_LIBM_FUNC([roundl], [x = roundl(x);], [], [
+ dnl No. Are both floorl() and ceill() available? If so then we can use
+ dnl them to implement roundl(), on the assumption that they're fast.
+ gl_CHECK_LIBM_FUNC([floorl], [x = floorl(x);], [
+ AC_CHECK_DECL([ceill],
+ [dnl Yes. Both are declared. Link against the necessary library.
+ ROUNDL_LIBM="$FLOORL_LIBM"],
+ [: dnl No. We will use an implementation that doesn't need them.
+], [#include <math.h>
+])])])])
diff --git a/modules/math b/modules/math
index 15e16e633f..540f2fa65a 100644
--- a/modules/math
+++ b/modules/math
@@ -30,6 +30,9 @@ math.h: math.in.h
-e 's|@''GNULIB_FREXPL''@|$(GNULIB_FREXPL)|g' \
-e 's|@''GNULIB_LDEXPL''@|$(GNULIB_LDEXPL)|g' \
-e 's|@''GNULIB_MATHL''@|$(GNULIB_MATHL)|g' \
+ -e 's|@''GNULIB_ROUND''@|$(GNULIB_ROUND)|g' \
+ -e 's|@''GNULIB_ROUNDF''@|$(GNULIB_ROUNDF)|g' \
+ -e 's|@''GNULIB_ROUNDL''@|$(GNULIB_ROUNDL)|g' \
-e 's|@''GNULIB_SIGNBIT''@|$(GNULIB_SIGNBIT)|g' \
-e 's|@''GNULIB_TRUNC''@|$(GNULIB_TRUNC)|g' \
-e 's|@''GNULIB_TRUNCF''@|$(GNULIB_TRUNCF)|g' \
@@ -46,6 +49,9 @@ math.h: math.in.h
-e 's|@''HAVE_DECL_FREXPL''@|$(HAVE_DECL_FREXPL)|g' \
-e 's|@''HAVE_DECL_LDEXPL''@|$(HAVE_DECL_LDEXPL)|g' \
-e 's|@''HAVE_DECL_LOGL''@|$(HAVE_DECL_LOGL)|g' \
+ -e 's|@''HAVE_DECL_ROUND''@|$(HAVE_DECL_ROUND)|g' \
+ -e 's|@''HAVE_DECL_ROUNDF''@|$(HAVE_DECL_ROUNDF)|g' \
+ -e 's|@''HAVE_DECL_ROUNDL''@|$(HAVE_DECL_ROUNDL)|g' \
-e 's|@''HAVE_DECL_SINL''@|$(HAVE_DECL_SINL)|g' \
-e 's|@''HAVE_DECL_SQRTL''@|$(HAVE_DECL_SQRTL)|g' \
-e 's|@''HAVE_DECL_TANL''@|$(HAVE_DECL_TANL)|g' \
diff --git a/modules/round b/modules/round
new file mode 100644
index 0000000000..0dd2526f87
--- /dev/null
+++ b/modules/round
@@ -0,0 +1,32 @@
+Description:
+round() function: round toward nearest, breaking ties away from zero.
+
+Files:
+lib/round.c
+m4/check-libm-func.m4
+m4/round.m4
+
+Depends-on:
+float
+floor
+math
+extensions
+
+configure.ac:
+gl_FUNC_ROUND
+gl_MATH_MODULE_INDICATOR([round])
+
+Makefile.am:
+
+Include:
+<math.h>
+
+Link:
+$(ROUND_LIBM)
+
+License:
+LGPL
+
+Maintainer:
+Ben Pfaff
+
diff --git a/modules/round-tests b/modules/round-tests
new file mode 100644
index 0000000000..d061431f19
--- /dev/null
+++ b/modules/round-tests
@@ -0,0 +1,21 @@
+Files:
+tests/test-round1.c
+tests/test-round2.c
+
+Depends-on:
+isnan-nolibm
+stdbool
+stdint
+fprintf-posix
+verify
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-round1 test-round2
+check_PROGRAMS += test-round1 test-round2
+test_round1_LDADD = $(LDADD) @ROUND_LIBM@
+test_round2_LDADD = $(LDADD) @ROUND_LIBM@
+
+License:
+LGPL
diff --git a/modules/roundf b/modules/roundf
new file mode 100644
index 0000000000..f24e347519
--- /dev/null
+++ b/modules/roundf
@@ -0,0 +1,32 @@
+Description:
+roundf() function: round toward nearest, breaking ties away from zero.
+
+Files:
+lib/round.c
+lib/roundf.c
+m4/check-libm-func.m4
+m4/roundf.m4
+
+Depends-on:
+float
+math
+extensions
+
+configure.ac:
+gl_FUNC_ROUNDF
+gl_MATH_MODULE_INDICATOR([roundf])
+
+Makefile.am:
+
+Include:
+<math.h>
+
+Link:
+$(ROUNDF_LIBM)
+
+License:
+LGPL
+
+Maintainer:
+Ben Pfaff
+
diff --git a/modules/roundf-tests b/modules/roundf-tests
new file mode 100644
index 0000000000..9fc69ebdcb
--- /dev/null
+++ b/modules/roundf-tests
@@ -0,0 +1,22 @@
+Files:
+tests/test-roundf1.c
+tests/test-round2.c
+tests/test-roundf2.c
+
+Depends-on:
+isnanf-nolibm
+stdbool
+stdint
+fprintf-posix
+verify
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-roundf1 test-roundf2
+check_PROGRAMS += test-roundf1 test-roundf2
+test_roundf1_LDADD = $(LDADD) @ROUNDF_LIBM@
+test_roundf2_LDADD = $(LDADD) @ROUNDF_LIBM@
+
+License:
+LGPL
diff --git a/modules/roundl b/modules/roundl
new file mode 100644
index 0000000000..3533d0f28a
--- /dev/null
+++ b/modules/roundl
@@ -0,0 +1,32 @@
+Description:
+roundl() function: round toward nearest, breaking ties away from zero.
+
+Files:
+lib/round.c
+lib/roundl.c
+m4/check-libm-func.m4
+m4/roundl.m4
+
+Depends-on:
+float
+math
+extensions
+
+configure.ac:
+gl_FUNC_ROUNDL
+gl_MATH_MODULE_INDICATOR([roundl])
+
+Makefile.am:
+
+Include:
+<math.h>
+
+Link:
+$(ROUNDL_LIBM)
+
+License:
+LGPL
+
+Maintainer:
+Ben Pfaff
+
diff --git a/modules/roundl-tests b/modules/roundl-tests
new file mode 100644
index 0000000000..957c9341dd
--- /dev/null
+++ b/modules/roundl-tests
@@ -0,0 +1,16 @@
+Files:
+tests/test-roundl.c
+
+Depends-on:
+fpucw
+isnanl-nolibm
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-roundl
+check_PROGRAMS += test-roundl
+test_roundl_LDADD = $(LDADD) @ROUNDL_LIBM@
+
+License:
+LGPL
diff --git a/tests/test-round1.c b/tests/test-round1.c
new file mode 100644
index 0000000000..396fcc4b93
--- /dev/null
+++ b/tests/test-round1.c
@@ -0,0 +1,90 @@
+/* Test of rounding to nearest, breaking ties away from 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 Ben Pfaff <blp@gnu.org>, 2007.
+ Based heavily on Bruno Haible's test-trunc.c. */
+
+#include <config.h>
+
+#include <math.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ASSERT(expr) \
+ do \
+ { \
+ if (!(expr)) \
+ { \
+ fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
+ abort (); \
+ } \
+ } \
+ while (0)
+
+/* The Compaq (ex-DEC) C 6.4 compiler chokes on the expression 0.0 / 0.0. */
+#ifdef __DECC
+static double
+NaN ()
+{
+ static double zero = 0.0;
+ return zero / zero;
+}
+#else
+# define NaN() (0.0 / 0.0)
+#endif
+
+int
+main ()
+{
+ /* Zero. */
+ ASSERT (round (0.0) == 0.0);
+ ASSERT (round (-0.0) == 0.0);
+ /* Positive numbers. */
+ ASSERT (round (0.3) == 0.0);
+ ASSERT (round (0.5) == 1.0);
+ ASSERT (round (0.7) == 1.0);
+ ASSERT (round (1.0) == 1.0);
+ ASSERT (round (1.5) == 2.0);
+ ASSERT (round (2.5) == 3.0);
+ ASSERT (round (1.999) == 2.0);
+ ASSERT (round (2.0) == 2.0);
+ ASSERT (round (65535.999) == 65536.0);
+ ASSERT (round (65536.0) == 65536.0);
+ ASSERT (round (65536.001) == 65536.0);
+ ASSERT (round (2.341e31) == 2.341e31);
+ /* Negative numbers. */
+ ASSERT (round (-0.3) == 0.0);
+ ASSERT (round (-0.5) == -1.0);
+ ASSERT (round (-0.7) == -1.0);
+ ASSERT (round (-1.0) == -1.0);
+ ASSERT (round (-1.5) == -2.0);
+ ASSERT (round (-2.5) == -3.0);
+ ASSERT (round (-1.999) == -2.0);
+ ASSERT (round (-2.0) == -2.0);
+ ASSERT (round (-65535.999) == -65536.0);
+ ASSERT (round (-65536.0) == -65536.0);
+ ASSERT (round (-65536.001) == -65536.0);
+ ASSERT (round (-2.341e31) == -2.341e31);
+ /* Infinite numbers. */
+ ASSERT (round (1.0 / 0.0) == 1.0 / 0.0);
+ ASSERT (round (-1.0 / 0.0) == -1.0 / 0.0);
+ /* NaNs. */
+ ASSERT (isnan (round (NaN ())));
+
+ return 0;
+}
diff --git a/tests/test-round2.c b/tests/test-round2.c
new file mode 100644
index 0000000000..1da0d9f8c5
--- /dev/null
+++ b/tests/test-round2.c
@@ -0,0 +1,108 @@
+/* Test of rounding to nearest, breaking ties away from 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 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/>. */
+
+/* Written by Ben Pfaff <blp@gnu.org>, 2007.
+ Heavily based on code by Bruno Haible. */
+
+/* Get the two reference implementations of round under the names
+ round_reference1 and round_reference2.
+
+ round.c will #include <config.h> for us. */
+#define FLOOR_BASED_ROUND round_reference1
+#define FLOOR_FREE_ROUND round_reference2
+#include "round.c"
+
+#include <math.h>
+#include <float.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "verify.h"
+
+#ifdef USE_LONG_DOUBLE
+# error Long double not supported.
+#elif ! defined USE_FLOAT
+# include "isnan.h"
+# define ISNAN isnan
+# define FUNCTION "round"
+# define DOUBLE_UINT uint64_t
+# define DOUBLE_BITS 64
+# define NUM_HIGHBITS 13
+# define NUM_LOWBITS 4
+#else /* defined USE_FLOAT */
+# include "isnanf.h"
+# define ISNAN isnanf
+# define FUNCTION "roundf"
+# define DOUBLE_UINT uint32_t
+# define DOUBLE_BITS 32
+# define NUM_HIGHBITS 12
+# define NUM_LOWBITS 4
+#endif
+
+/* Test for equality. */
+static bool
+equal (const char *message, DOUBLE x, DOUBLE y0, DOUBLE y1)
+{
+ if (ISNAN (y0) ? ISNAN (y1) : y0 == y1)
+ return true;
+ else
+ {
+ fprintf (stderr, "%s: "FUNCTION"(%g(%a)) = %g(%a) or %g(%a)?\n",
+ message, x, x, y0, y0, y1, y1);
+ return false;
+ }
+}
+
+/* Test the function for a given argument. */
+static bool
+check (DOUBLE x)
+{
+ DOUBLE ref1 = round_reference1 (x);
+ DOUBLE ref2 = round_reference2 (x);
+ DOUBLE result = round (x);
+
+ /* If the reference implementations disagree, bail out immediately. */
+ if (!equal ("reference implementations disagree", x, ref1, ref2))
+ exit (EXIT_FAILURE);
+
+ /* If the actual implementation is wrong, return an error code. */
+ return equal ("bad round implementation", x, ref1, result);
+}
+
+int
+main (void)
+{
+ DOUBLE_UINT highbits, lowbits;
+ int error = 0;
+ for (highbits = 0; highbits < (1 << NUM_HIGHBITS); highbits++)
+ for (lowbits = 0; lowbits < (1 << NUM_LOWBITS); lowbits++)
+ {
+ /* Combine highbits and lowbits into a floating-point number,
+ sign-extending the lowbits to DOUBLE_BITS-NUM_HIGHBITS bits. */
+ union { DOUBLE f; DOUBLE_UINT i; } janus;
+ verify (sizeof janus.f == sizeof janus.i);
+ janus.i = lowbits | (highbits << (DOUBLE_BITS - NUM_HIGHBITS));
+ if (lowbits >> (NUM_LOWBITS - 1))
+ janus.i |= ((DOUBLE_UINT) -1
+ >> (NUM_LOWBITS + NUM_HIGHBITS)
+ << NUM_LOWBITS);
+ if (!check (janus.f))
+ error = true;
+ }
+ return (error ? 1 : 0);
+}
diff --git a/tests/test-roundf1.c b/tests/test-roundf1.c
new file mode 100644
index 0000000000..6311e3a898
--- /dev/null
+++ b/tests/test-roundf1.c
@@ -0,0 +1,90 @@
+/* Test of rounding to nearest, breaking ties away from 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 Ben Pfaff <blp@gnu.org>, 2007.
+ Based heavily on Bruno Haible's test-truncf.c. */
+
+#include <config.h>
+
+#include <math.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ASSERT(expr) \
+ do \
+ { \
+ if (!(expr)) \
+ { \
+ fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
+ abort (); \
+ } \
+ } \
+ while (0)
+
+/* The Compaq (ex-DEC) C 6.4 compiler chokes on the expression 0.0 / 0.0. */
+#ifdef __DECC
+static float
+NaN ()
+{
+ static float zero = 0.0f;
+ return zero / zero;
+}
+#else
+# define NaN() (0.0f / 0.0f)
+#endif
+
+int
+main ()
+{
+ /* Zero. */
+ ASSERT (roundf (0.0f) == 0.0f);
+ ASSERT (roundf (-0.0f) == 0.0f);
+ /* Positive numbers. */
+ ASSERT (roundf (0.3f) == 0.0f);
+ ASSERT (roundf (0.5f) == 1.0f);
+ ASSERT (roundf (0.7f) == 1.0f);
+ ASSERT (roundf (1.0f) == 1.0f);
+ ASSERT (roundf (1.5f) == 2.0f);
+ ASSERT (roundf (2.5f) == 3.0f);
+ ASSERT (roundf (1.999f) == 2.0f);
+ ASSERT (roundf (2.0f) == 2.0f);
+ ASSERT (roundf (65535.99f) == 65536.0f);
+ ASSERT (roundf (65536.0f) == 65536.0f);
+ ASSERT (roundf (65536.01f) == 65536.0f);
+ ASSERT (roundf (2.341e31f) == 2.341e31f);
+ /* Negative numbers. */
+ ASSERT (roundf (-0.3f) == 0.0f);
+ ASSERT (roundf (-0.5f) == -1.0f);
+ ASSERT (roundf (-0.7f) == -1.0f);
+ ASSERT (roundf (-1.0f) == -1.0f);
+ ASSERT (roundf (-1.5f) == -2.0f);
+ ASSERT (roundf (-2.5f) == -3.0f);
+ ASSERT (roundf (-1.999f) == -2.0f);
+ ASSERT (roundf (-2.0f) == -2.0f);
+ ASSERT (roundf (-65535.99f) == -65536.0f);
+ ASSERT (roundf (-65536.0f) == -65536.0f);
+ ASSERT (roundf (-65536.01f) == -65536.0f);
+ ASSERT (roundf (-2.341e31f) == -2.341e31f);
+ /* Infinite numbers. */
+ ASSERT (roundf (1.0 / 0.0f) == 1.0 / 0.0f);
+ ASSERT (roundf (-1.0 / 0.0f) == -1.0 / 0.0f);
+ /* NaNs. */
+ ASSERT (isnan (roundf (NaN ())));
+
+ return 0;
+}
diff --git a/tests/test-roundf2.c b/tests/test-roundf2.c
new file mode 100644
index 0000000000..5688d9337a
--- /dev/null
+++ b/tests/test-roundf2.c
@@ -0,0 +1,2 @@
+#define USE_FLOAT
+#include "test-round2.c"
diff --git a/tests/test-roundl.c b/tests/test-roundl.c
new file mode 100644
index 0000000000..1495eaed9e
--- /dev/null
+++ b/tests/test-roundl.c
@@ -0,0 +1,85 @@
+/* Test of rounding to nearest, breaking ties away from 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 Ben Pfaff <blp@gnu.org>, 2007.
+ Based heavily on Bruno Haible's test-truncl.c. */
+
+#include <config.h>
+
+#include <math.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "fpucw.h"
+#include "isnanl-nolibm.h"
+
+#define ASSERT(expr) \
+ do \
+ { \
+ if (!(expr)) \
+ { \
+ fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
+ abort (); \
+ } \
+ } \
+ while (0)
+
+int
+main ()
+{
+ DECL_LONG_DOUBLE_ROUNDING
+
+ BEGIN_LONG_DOUBLE_ROUNDING ();
+
+ /* Zero. */
+ ASSERT (roundl (0.0L) == 0.0L);
+ ASSERT (roundl (-0.0L) == 0.0L);
+ /* Positive numbers. */
+ ASSERT (roundl (0.3L) == 0.0L);
+ ASSERT (roundl (0.5L) == 1.0L);
+ ASSERT (roundl (0.7L) == 1.0L);
+ ASSERT (roundl (1.0L) == 1.0L);
+ ASSERT (roundl (1.5L) == 2.0L);
+ ASSERT (roundl (2.5L) == 3.0L);
+ ASSERT (roundl (1.999L) == 2.0L);
+ ASSERT (roundl (2.0L) == 2.0L);
+ ASSERT (roundl (65535.999L) == 65536.0L);
+ ASSERT (roundl (65536.0L) == 65536.0L);
+ ASSERT (roundl (65536.001L) == 65536.0L);
+ ASSERT (roundl (2.341e31L) == 2.341e31L);
+ /* Negative numbers. */
+ ASSERT (roundl (-0.3L) == 0.0L);
+ ASSERT (roundl (-0.5L) == -1.0L);
+ ASSERT (roundl (-0.7L) == -1.0L);
+ ASSERT (roundl (-1.0L) == -1.0L);
+ ASSERT (roundl (-1.5L) == -2.0L);
+ ASSERT (roundl (-2.5L) == -3.0L);
+ ASSERT (roundl (-1.999L) == -2.0L);
+ ASSERT (roundl (-2.0L) == -2.0L);
+ ASSERT (roundl (-65535.999L) == -65536.0L);
+ ASSERT (roundl (-65536.0L) == -65536.0L);
+ ASSERT (roundl (-65536.001L) == -65536.0L);
+ ASSERT (roundl (-2.341e31L) == -2.341e31L);
+ /* Infinite numbers. */
+ ASSERT (roundl (1.0 / 0.0L) == 1.0 / 0.0L);
+ ASSERT (roundl (-1.0 / 0.0L) == -1.0 / 0.0L);
+ /* NaNs. */
+ ASSERT (isnanl (roundl (0.0L / 0.0L)));
+
+ return 0;
+}