From 33d6a0e5ca06c6d0a8b0fddba8c7f41bbd6794ae Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sat, 13 Oct 2007 02:51:46 +0200 Subject: [PATCH] Fix incorrect rounding of floor, floorf, floorl in some cases. Add new test. --- ChangeLog | 5 +++++ lib/floor.c | 29 ++++++++++++++++++++--------- modules/floorf-tests | 10 ++++++++-- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index 288623676..7857f6ed1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2007-10-12 Bruno Haible + * 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. diff --git a/lib/floor.c b/lib/floor.c index 7ee748601..05a6591a4 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; } diff --git a/modules/floorf-tests b/modules/floorf-tests index c8a97a858..02a5ca28c 100644 --- 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 -- 2.11.0