changeset 9332:b72a5920bf45

Fix incorrect rounding of floor, floorf, floorl in some cases. Add new test.
author Bruno Haible <bruno@clisp.org>
date Sat, 13 Oct 2007 02:51:46 +0200
parents 1456df727e8e
children edb32d574f8d
files ChangeLog lib/floor.c modules/floorf-tests
diffstat 3 files changed, 33 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2007-10-12  Bruno Haible  <bruno@clisp.org>
 
+	* lib/floor.c (FUNC): Avoid rounding errors for values near a power
+	of 2.
+	* tests/test-floorf2.c: New file.
+	* modules/floorf-tests: (Files, Depends-on, Makefile.am): Add new test.
+
 	* tests/test-floorf1.c: Renamed from tests/test-floorf.c.
 	* modules/floorf-tests: Update.
 
--- a/lib/floor.c
+++ b/lib/floor.c
@@ -63,20 +63,31 @@
   volatile DOUBLE y = x;
   volatile DOUBLE z = y;
 
-  /* Round to the next integer (nearest or up or down, doesn't matter).  */
   if (z > L_(0.0))
     {
-      z += TWO_MANT_DIG;
-      z -= TWO_MANT_DIG;
+      /* Avoid rounding errors for values near 2^k, where k >= MANT_DIG-1.  */
+      if (z < TWO_MANT_DIG)
+	{
+	  /* 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))
     {
-      z -= TWO_MANT_DIG;
-      z += TWO_MANT_DIG;
+      /* Avoid rounding errors for values near -2^k, where k >= MANT_DIG-1.  */
+      if (z > - TWO_MANT_DIG)
+	{
+	  /* 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);
+	}
     }
-  /* Enforce rounding down.  */
-  if (z > y)
-    z -= L_(1.0);
-
   return z;
 }
--- a/modules/floorf-tests
+++ b/modules/floorf-tests
@@ -1,14 +1,20 @@
 Files:
 tests/test-floorf1.c
+tests/test-floorf2.c
 
 Depends-on:
+float
+isnanf-nolibm
+stdbool
+stdint
 
 configure.ac:
 
 Makefile.am:
-TESTS += test-floorf1
-check_PROGRAMS += test-floorf1
+TESTS += test-floorf1 test-floorf2
+check_PROGRAMS += test-floorf1 test-floorf2
 test_floorf1_LDADD = $(LDADD) @FLOORF_LIBM@
+test_floorf2_LDADD = $(LDADD) @FLOORF_LIBM@
 
 License:
 LGPL