From: Bruno Haible Date: Sun, 4 Mar 2012 22:07:45 +0000 (+0100) Subject: remainder* tests: More tests. X-Git-Tag: v0.1~957 X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=5eb8c1aaacc36b33fce63f8e9f15175997bb1fa4;p=gnulib.git remainder* tests: More tests. * tests/test-remainder.h: New file, based on tests/test-fmod.h. * tests/test-remainder.c: Include and test-remainder.h. (main): Invoke test_function. * tests/test-remainderf.c: Include and test-remainder.h. (main): Invoke test_function. * tests/test-remainderl.c: Include and test-remainder.h. (main): Invoke test_function. * modules/remainder-tests (Files): Add tests/test-remainder.h, tests/randomd.c. (Makefile.am): Add randomd.c to test_remainder_SOURCES. * modules/remainderf-tests (Files): Add tests/test-remainder.h, tests/randomf.c. (Makefile.am): Add randomf.c to test_remainderf_SOURCES. * modules/remainderl-tests (Files): Add tests/test-remainder.h, tests/randoml.c. (Depends-on): Add 'float'. (Makefile.am): Add randoml.c to test_remainderl_SOURCES. --- diff --git a/ChangeLog b/ChangeLog index e7139c0605..7a01288dd7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2012-03-03 Bruno Haible + + remainder* tests: More tests. + * tests/test-remainder.h: New file, based on tests/test-fmod.h. + * tests/test-remainder.c: Include and test-remainder.h. + (main): Invoke test_function. + * tests/test-remainderf.c: Include and test-remainder.h. + (main): Invoke test_function. + * tests/test-remainderl.c: Include and test-remainder.h. + (main): Invoke test_function. + * modules/remainder-tests (Files): Add tests/test-remainder.h, + tests/randomd.c. + (Makefile.am): Add randomd.c to test_remainder_SOURCES. + * modules/remainderf-tests (Files): Add tests/test-remainder.h, + tests/randomf.c. + (Makefile.am): Add randomf.c to test_remainderf_SOURCES. + * modules/remainderl-tests (Files): Add tests/test-remainder.h, + tests/randoml.c. + (Depends-on): Add 'float'. + (Makefile.am): Add randoml.c to test_remainderl_SOURCES. + 2012-03-04 Bruno Haible remainder, remainderf, remainderl: Fix computation for large quotients. diff --git a/modules/remainder-tests b/modules/remainder-tests index 6832a49add..0ede99ab39 100644 --- a/modules/remainder-tests +++ b/modules/remainder-tests @@ -1,7 +1,9 @@ Files: tests/test-remainder.c +tests/test-remainder.h tests/signature.h tests/macros.h +tests/randomd.c Depends-on: @@ -10,4 +12,5 @@ configure.ac: Makefile.am: TESTS += test-remainder check_PROGRAMS += test-remainder +test_remainder_SOURCES = test-remainder.c randomd.c test_remainder_LDADD = $(LDADD) @REMAINDER_LIBM@ diff --git a/modules/remainderf-tests b/modules/remainderf-tests index 6f392da43e..7958022073 100644 --- a/modules/remainderf-tests +++ b/modules/remainderf-tests @@ -1,7 +1,9 @@ Files: tests/test-remainderf.c +tests/test-remainder.h tests/signature.h tests/macros.h +tests/randomf.c Depends-on: @@ -10,4 +12,5 @@ configure.ac: Makefile.am: TESTS += test-remainderf check_PROGRAMS += test-remainderf +test_remainderf_SOURCES = test-remainderf.c randomf.c test_remainderf_LDADD = $(LDADD) @REMAINDERF_LIBM@ diff --git a/modules/remainderl-tests b/modules/remainderl-tests index 4a638aa442..533930e01d 100644 --- a/modules/remainderl-tests +++ b/modules/remainderl-tests @@ -1,14 +1,18 @@ Files: tests/test-remainderl.c +tests/test-remainder.h tests/signature.h tests/macros.h +tests/randoml.c Depends-on: fpucw +float configure.ac: Makefile.am: TESTS += test-remainderl check_PROGRAMS += test-remainderl +test_remainderl_SOURCES = test-remainderl.c randoml.c test_remainderl_LDADD = $(LDADD) @REMAINDERL_LIBM@ diff --git a/tests/test-remainder.c b/tests/test-remainder.c index 5869bb7d73..c43d60639f 100644 --- a/tests/test-remainder.c +++ b/tests/test-remainder.c @@ -23,11 +23,17 @@ #include "signature.h" SIGNATURE_CHECK (remainder, double, (double, double)); +#include + #include "macros.h" -volatile double x; -volatile double y; -double z; +#define DOUBLE double +#define L_(literal) literal +#define MANT_DIG DBL_MANT_DIG +#define MAX_EXP DBL_MAX_EXP +#define REMAINDER remainder +#define RANDOM randomd +#include "test-remainder.h" int main () @@ -38,5 +44,7 @@ main () z = remainder (x, y); ASSERT (z >= -0.178870837 && z <= -0.178870835); + test_function (); + return 0; } diff --git a/tests/test-remainder.h b/tests/test-remainder.h new file mode 100644 index 0000000000..a25e6b22bb --- /dev/null +++ b/tests/test-remainder.h @@ -0,0 +1,124 @@ +/* Test of remainder*() function family. + Copyright (C) 2012 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 . */ + +static DOUBLE +my_ldexp (DOUBLE x, int d) +{ + for (; d > 0; d--) + x *= L_(2.0); + for (; d < 0; d++) + x *= L_(0.5); + return x; +} + +static void +test_function (void) +{ + int i; + int j; + 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)); + + /* Randomized tests. */ + for (i = 0; i < SIZEOF (RANDOM) / 5; i++) + for (j = 0; j < SIZEOF (RANDOM) / 5; j++) + { + DOUBLE x = L_(16.0) * RANDOM[i]; /* 0.0 <= x <= 16.0 */ + DOUBLE y = RANDOM[j]; /* 0.0 <= y < 1.0 */ + if (y > L_(0.0)) + { + DOUBLE z = REMAINDER (x, y); + ASSERT (z >= - L_(0.5) * y); + ASSERT (z <= L_(0.5) * y); + z -= x - (int) ((L_(2.0) * x + y) / (L_(2.0) * y)) * y; + ASSERT (/* The common case. */ + (z > - L_(2.0) * L_(16.0) / TWO_MANT_DIG + && z < L_(2.0) * L_(16.0) / TWO_MANT_DIG) + || /* rounding error: 2x+y / 2y computed too large */ + (z > y - L_(2.0) * L_(16.0) / TWO_MANT_DIG + && z < y + L_(2.0) * L_(16.0) / TWO_MANT_DIG) + || /* rounding error: 2x+y / 2y computed too small */ + (z > - y - L_(2.0) * L_(16.0) / TWO_MANT_DIG + && z < - y + L_(2.0) * L_(16.0) / TWO_MANT_DIG)); + } + } + + for (i = 0; i < SIZEOF (RANDOM) / 5; i++) + for (j = 0; j < SIZEOF (RANDOM) / 5; j++) + { + DOUBLE x = L_(1.0e9) * RANDOM[i]; /* 0.0 <= x <= 10^9 */ + DOUBLE y = RANDOM[j]; /* 0.0 <= y < 1.0 */ + if (y > L_(0.0)) + { + DOUBLE z = REMAINDER (x, y); + DOUBLE r; + ASSERT (z >= - L_(0.5) * y); + ASSERT (z <= L_(0.5) * y); + { + /* Determine the quotient 2x+y / 2y in two steps, because it + may be > 2^31. */ + int q1 = (int) (x / y / L_(65536.0)); + int q2 = (int) ((L_(2.0) * (x - q1 * L_(65536.0) * y) + y) + / (L_(2.0) * y)); + DOUBLE q = (DOUBLE) q1 * L_(65536.0) + (DOUBLE) q2; + r = x - q * y; + } + /* The absolute error of z can be up to 1e9/2^MANT_DIG. + The absolute error of r can also be up to 1e9/2^MANT_DIG. + Therefore the error of z - r can be twice as large. */ + z -= r; + ASSERT (/* The common case. */ + (z > - L_(2.0) * L_(1.0e9) / TWO_MANT_DIG + && z < L_(2.0) * L_(1.0e9) / TWO_MANT_DIG) + || /* rounding error: 2x+y / 2y computed too large */ + (z > y - L_(2.0) * L_(1.0e9) / TWO_MANT_DIG + && z < y + L_(2.0) * L_(1.0e9) / TWO_MANT_DIG) + || /* rounding error: 2x+y / 2y computed too small */ + (z > - y - L_(2.0) * L_(1.0e9) / TWO_MANT_DIG + && z < - y + L_(2.0) * L_(1.0e9) / TWO_MANT_DIG)); + } + } + + { + int large_exp = (MAX_EXP - 1 < 1000 ? MAX_EXP - 1 : 1000); + DOUBLE large = my_ldexp (L_(1.0), large_exp); /* = 2^large_exp */ + for (i = 0; i < SIZEOF (RANDOM) / 10; i++) + for (j = 0; j < SIZEOF (RANDOM) / 10; j++) + { + DOUBLE x = large * RANDOM[i]; /* 0.0 <= x <= 2^large_exp */ + DOUBLE y = RANDOM[j]; /* 0.0 <= y < 1.0 */ + if (y > L_(0.0)) + { + DOUBLE z = REMAINDER (x, y); + /* Regardless how large the rounding errors are, the result + must be >= -y/2, <= y/2. */ + ASSERT (z >= - L_(0.5) * y); + ASSERT (z <= L_(0.5) * y); + } + } + } +} + +volatile DOUBLE x; +volatile DOUBLE y; +DOUBLE z; diff --git a/tests/test-remainderf.c b/tests/test-remainderf.c index fc6be7568a..0c6174fb86 100644 --- a/tests/test-remainderf.c +++ b/tests/test-remainderf.c @@ -23,11 +23,17 @@ #include "signature.h" SIGNATURE_CHECK (remainderf, float, (float, float)); +#include + #include "macros.h" -volatile float x; -volatile float y; -float z; +#define DOUBLE float +#define L_(literal) literal##f +#define MANT_DIG FLT_MANT_DIG +#define MAX_EXP FLT_MAX_EXP +#define REMAINDER remainderf +#define RANDOM randomf +#include "test-remainder.h" int main () @@ -37,5 +43,8 @@ main () y = 3.141592654f; z = remainderf (x, y); ASSERT (z >= -0.1788714f && z <= -0.1788708f); + + test_function (); + return 0; } diff --git a/tests/test-remainderl.c b/tests/test-remainderl.c index 3307d8064e..09dc7c7263 100644 --- a/tests/test-remainderl.c +++ b/tests/test-remainderl.c @@ -23,12 +23,18 @@ #include "signature.h" SIGNATURE_CHECK (remainderl, long double, (long double, long double)); +#include + #include "fpucw.h" #include "macros.h" -volatile long double x; -volatile long double y; -long double z; +#define DOUBLE long double +#define L_(literal) literal##L +#define MANT_DIG LDBL_MANT_DIG +#define MAX_EXP LDBL_MAX_EXP +#define REMAINDER remainderl +#define RANDOM randoml +#include "test-remainder.h" int main () @@ -43,5 +49,7 @@ main () z = remainderl (x, y); ASSERT (z >= -0.178870837L && z <= -0.178870835L); + test_function (); + return 0; }