bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

'round' modules takes 3 (was: Re: modules 'round', 'roundf', 'roundl' fo


From: Ben Pfaff
Subject: 'round' modules takes 3 (was: Re: modules 'round', 'roundf', 'roundl' for review)
Date: Fri, 19 Oct 2007 19:29:42 -0700
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.1 (gnu/linux)

Bruno Haible <address@hidden> writes:

> 1) test them both as reference implementations, like done in test-truncf2.c
>    and test-trunc2.c.
> 2) use round_bruno1 as the implementation in lib/round.c if the corresponding
>    functions floor, ceil (or floorf, ceilf, or floorl, ceill) are not
>    declared. If they are declared, one can assume that they are efficiently
>    implemented, and then round_blp looks like quite efficient.

Thank you for the suggestions, which sound very reasonable to me.
I've been short on time to work on free software projects over
the last week, but I've now implemented these suggestions.  Here
is the new patch.  I am pretty confident about the C code but, as
always, my m4 code can use some looking over.

I wasn't happy to imitate all the code duplication among trunc.c,
test-trunc2.c, and test-truncf2.c, so instead I used a few macros
to avoid it.  In the test code, I also didn't want to depend on a
right-shift of a negative number producing sign-extension (it is
not a C standard requirement and Autoconf manual warns against
it), so I used slightly different code in that part of the test.

Finally, I noticed a nit in that test-trunc2 and test-truncf2 use
%a in fprintf, a C99 feature, but do not depend on fprintf-posix.
I did add that dependency to round-tests and roundf-tests.

diff --git a/MODULES.html.sh b/MODULES.html.sh
index 7934cc9..11c4e3e 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 9910e23..28eb574 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
address@hidden
+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
address@hidden
-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 f389a64..41b3a7f 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
address@hidden
+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
address@hidden
-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 439a0a8..a4eaa7d 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
address@hidden
+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
address@hidden
-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 93eeb93..c5d98f0 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 address@hidden@
+#  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 address@hidden@
+#  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 address@hidden@
+#  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@ || address@hidden@
 extern long double sinl (long double x);
 #endif
diff --git a/lib/round.c b/lib/round.c
new file mode 100644
index 0000000..a9fd393
--- /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 <address@hidden>, 2007.
+   Based heavily on code by Bruno Haible. */
+
+#include <config.h>
+
+/* Specification.  */
+#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 0000000..8d7f94b
--- /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 0000000..e53ac0a
--- /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 0000000..e375558
--- /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 5539d79..4806e08 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 0000000..4914aac
--- /dev/null
+++ b/m4/round.m4
@@ -0,0 +1,39 @@
+# 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);], [], [
+    dnl Test whether floor() can be used without libm.
+    ROUND_LIBM=?
+    AC_TRY_LINK([
+       #ifndef __NO_MATH_INLINES
+       # define __NO_MATH_INLINES 1 /* for glibc */
+       #endif
+       #include <math.h>
+       double x;],
+      [x = floor(x);],
+      [ROUND_LIBM=])
+    if test "$ROUND_LIBM" = "?"; then
+      save_LIBS="$LIBS"
+      LIBS="$LIBS -lm"
+      AC_TRY_LINK([
+         #ifndef __NO_MATH_INLINES
+         # define __NO_MATH_INLINES 1 /* for glibc */
+         #endif
+         #include <math.h>
+         double x;],
+        [x = floor(x);],
+        [ROUND_LIBM="-lm"])
+      LIBS="$save_LIBS"
+    fi
+    if test "$ROUND_LIBM" = "?"; then
+      ROUND_LIBM=
+    fi
+    AC_LIBOBJ([round])])])
diff --git a/m4/roundf.m4 b/m4/roundf.m4
new file mode 100644
index 0000000..57778a8
--- /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 0000000..6bec36b
--- /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 15e16e6..540f2fa 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 0000000..4bb01a9
--- /dev/null
+++ b/modules/round
@@ -0,0 +1,31 @@
+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
+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 0000000..2ba583e
--- /dev/null
+++ b/modules/round-tests
@@ -0,0 +1,20 @@
+Files:
+tests/test-round1.c
+tests/test-round2.c
+
+Depends-on:
+isnan-nolibm
+stdbool
+stdint
+fprintf-posix
+
+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 0000000..f24e347
--- /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 0000000..8f9ef53
--- /dev/null
+++ b/modules/roundf-tests
@@ -0,0 +1,21 @@
+Files:
+tests/test-roundf1.c
+tests/test-round2.c
+tests/test-roundf2.c
+
+Depends-on:
+isnanf-nolibm
+stdbool
+stdint
+fprintf-posix
+
+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 0000000..3533d0f
--- /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 0000000..957c934
--- /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 0000000..396fcc4
--- /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 <address@hidden>, 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 0000000..9c07a5f
--- /dev/null
+++ b/tests/test-round2.c
@@ -0,0 +1,107 @@
+/* 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 <address@hidden>, 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 <assert.h>
+#include <math.h>
+
+#include <float.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.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, midbits;
+  int error = 0;
+  midbits = ((DOUBLE_UINT) -1) >> (NUM_LOWBITS + NUM_HIGHBITS) << NUM_LOWBITS;
+  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;
+        assert (sizeof janus.f == sizeof janus.i);
+        janus.i = lowbits | (highbits << (DOUBLE_BITS - NUM_HIGHBITS));
+        if (lowbits >> (NUM_LOWBITS - 1))
+          janus.i |= midbits;
+       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 0000000..6311e3a
--- /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 <address@hidden>, 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 0000000..5688d93
--- /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 0000000..1495eae
--- /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 <address@hidden>, 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;
+}

-- 
"...dans ce pays-ci il est bon de tuer de temps en temps un amiral
 pour encourager les autres."
--Voltaire, _Candide_





reply via email to

[Prev in Thread] Current Thread [Next in Thread]