summaryrefslogtreecommitdiff
path: root/lib/floor.c
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2007-10-13 02:51:46 +0200
committerBruno Haible <bruno@clisp.org>2007-10-13 02:51:46 +0200
commit33d6a0e5ca06c6d0a8b0fddba8c7f41bbd6794ae (patch)
treef5465ba662e635ac6c9a761d9d4a6876e8e6cc5d /lib/floor.c
parent7a9376508b5cf731a98a66e4021aa9d0167ef723 (diff)
downloadgnulib-33d6a0e5ca06c6d0a8b0fddba8c7f41bbd6794ae.tar.gz
Fix incorrect rounding of floor, floorf, floorl in some cases. Add new test.
Diffstat (limited to 'lib/floor.c')
-rw-r--r--lib/floor.c29
1 files changed, 20 insertions, 9 deletions
diff --git a/lib/floor.c b/lib/floor.c
index 7ee748601d..05a6591a4b 100644
--- a/lib/floor.c
+++ b/lib/floor.c
@@ -63,20 +63,31 @@ FUNC (DOUBLE x)
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;
}