changeset 9375:96fea5b2eb11

Implement 'round', 'roundf', 'roundl' modules.
author Ben Pfaff <blp@cs.stanford.edu>
date Sat, 20 Oct 2007 13:08:26 -0700
parents f3d25691c7ac
children 15917bb4d078
files ChangeLog MODULES.html.sh doc/functions/round.texi doc/functions/roundf.texi doc/functions/roundl.texi lib/math.in.h lib/round.c lib/roundf.c lib/roundl.c m4/check-libm-func.m4 m4/math_h.m4 m4/round.m4 m4/roundf.m4 m4/roundl.m4 modules/math modules/round modules/round-tests modules/roundf modules/roundf-tests modules/roundl modules/roundl-tests tests/test-round1.c tests/test-round2.c tests/test-roundf1.c tests/test-roundf2.c tests/test-roundl.c
diffstat 26 files changed, 934 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- 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.
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -1977,6 +1977,9 @@
   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
--- 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
-@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
+
+Portability problems not fixed by Gnulib:
+@itemize
+@end itemize
--- 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
-@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
+
+Portability problems not fixed by Gnulib:
+@itemize
+@end itemize
--- 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
-@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
+
+Portability problems not fixed by Gnulib:
+@itemize
+@end itemize
--- a/lib/math.in.h
+++ b/lib/math.in.h
@@ -217,6 +217,48 @@
 #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
new file mode 100644
--- /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 */
+
new file mode 100644
--- /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"
new file mode 100644
--- /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"
new file mode 100644
--- /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])])
--- a/m4/math_h.m4
+++ b/m4/math_h.m4
@@ -27,6 +27,9 @@
   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 @@
   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])
new file mode 100644
--- /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])])])
new file mode 100644
--- /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>
+])])])])
new file mode 100644
--- /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>
+])])])])
--- a/modules/math
+++ b/modules/math
@@ -30,6 +30,9 @@
 	      -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 @@
 	      -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' \
new file mode 100644
--- /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
+
new file mode 100644
--- /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
new file mode 100644
--- /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
+
new file mode 100644
--- /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
new file mode 100644
--- /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
+
new file mode 100644
--- /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
new file mode 100644
--- /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;
+}
new file mode 100644
--- /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);
+}
new file mode 100644
--- /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;
+}
new file mode 100644
--- /dev/null
+++ b/tests/test-roundf2.c
@@ -0,0 +1,2 @@
+#define USE_FLOAT
+#include "test-round2.c"
new file mode 100644
--- /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;
+}