summaryrefslogtreecommitdiff
path: root/tests/trint.c
diff options
context:
space:
mode:
author(no author) <(no author)@280ebfd0-de03-0410-8827-d642c229c3f4>2003-11-21 13:23:58 +0000
committer(no author) <(no author)@280ebfd0-de03-0410-8827-d642c229c3f4>2003-11-21 13:23:58 +0000
commit106c460c60e3f1a9a47890589532d491fc091c8f (patch)
tree1eae41db56c148139a4a097a2410924a0f28f830 /tests/trint.c
parent7f857964d869e4a3f316a7da845e11a9da0388a5 (diff)
downloadmpfr-106c460c60e3f1a9a47890589532d491fc091c8f.tar.gz
This commit was manufactured by cvs2svn to create tagmpfr-2-0-2-rel
'mpfr-2-0-2-rel'. git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/tags/mpfr-2-0-2-rel@2561 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'tests/trint.c')
-rw-r--r--tests/trint.c205
1 files changed, 177 insertions, 28 deletions
diff --git a/tests/trint.c b/tests/trint.c
index e8a47cefa..b02b42221 100644
--- a/tests/trint.c
+++ b/tests/trint.c
@@ -1,4 +1,4 @@
-/* Test file for mpfr_trunc, mpfr_floor, mpfr_ceil, mpfr_round.
+/* Test file for mpfr_rint, mpfr_trunc, mpfr_floor, mpfr_ceil, mpfr_round.
Copyright 2002, 2003 Free Software Foundation.
@@ -21,17 +21,84 @@ MA 02111-1307, USA. */
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "gmp.h"
+#include "gmp-impl.h"
#include "mpfr.h"
+#include "mpfr-impl.h"
#include "mpfr-test.h"
+#if __STDC_VERSION__ >= 199901L
+
+static void
+test_fct (double (*f)(double), int (*g)(), char *s, mp_rnd_t r)
+{
+ double d, y;
+ mpfr_t dd, yy;
+
+ mpfr_init2 (dd, 53);
+ mpfr_init2 (yy, 53);
+ for (d = -5.0; d <= 5.0; d += 0.25)
+ {
+ mpfr_set_d (dd, d, r);
+ y = (*f)(d);
+ if (g == &mpfr_rint)
+ mpfr_rint (yy, dd, r);
+ else
+ (*g)(yy, dd);
+ mpfr_set_d (dd, y, r);
+ if (mpfr_cmp (yy, dd))
+ {
+ printf ("test_against_libc: incorrect result for %s, rnd = %s,"
+ " d = %g\ngot ", s, mpfr_print_rnd_mode (r), d);
+ mpfr_out_str (stdout, 10, 0, yy, GMP_RNDN);
+ printf (" instead of %g\n", y);
+ exit (1);
+ }
+ }
+ mpfr_clear (dd);
+ mpfr_clear (yy);
+}
+
+#define TEST_FCT(F) test_fct (&F, &mpfr_##F, #F, r)
+
+static void
+test_against_libc (void)
+{
+ int r = 0;
+
+ TEST_FCT (round);
+ TEST_FCT (trunc);
+ TEST_FCT (floor);
+ TEST_FCT (ceil);
+ for (r = 0; r < 4; r++)
+ if (mpfr_set_machine_rnd_mode (r) == 0)
+ test_fct (&nearbyint, &mpfr_rint, "rint", r);
+}
+
+#endif
+
+static void
+err (char *str, mp_size_t s, mpfr_t x, mpfr_t y, mp_prec_t p, mp_rnd_t r,
+ int trint, int inexact)
+{
+ printf ("Error: %s\ns = %u, p = %u, r = %s, trint = %d, inexact = %d\nx = ",
+ str, (unsigned int) s, (unsigned int) p, mpfr_print_rnd_mode (r),
+ trint, inexact);
+ mpfr_print_binary (x);
+ printf ("\ny = ");
+ mpfr_print_binary (y);
+ printf ("\n");
+ exit (1);
+}
+
int
-main (void)
+main (int argc, char *argv[])
{
mp_size_t s;
mpz_t z;
mp_prec_t p;
- mpfr_t x, y, t;
+ mpfr_t x, y, t, u, v;
mp_rnd_t r;
int inexact, sign_t;
@@ -41,6 +108,8 @@ main (void)
mpfr_init (y);
mpz_init (z);
mpfr_init (t);
+ mpfr_init (u);
+ mpfr_init (v);
mpz_set_ui (z, 1);
for (s = 2; s < 100; s++)
{
@@ -51,45 +120,125 @@ main (void)
mpz_add_ui (z, z, 1);
mpfr_set_prec (x, s);
mpfr_set_prec (t, s);
+ mpfr_set_prec (u, s);
if (mpfr_set_z (x, z, GMP_RNDN))
{
printf ("Error: mpfr_set_z should be exact (s = %u)\n",
(unsigned int) s);
exit (1);
}
- for (p=2; p<100; p++)
+ if (randlimb () % 2)
+ mpfr_neg (x, x, GMP_RNDN);
+ if (randlimb () % 2)
+ mpfr_div_2ui (x, x, randlimb () % s, GMP_RNDN);
+ for (p = 2; p < 100; p++)
{
+ int trint;
mpfr_set_prec (y, p);
- for (r=0; r<4; r++)
- {
- if (r == GMP_RNDN)
- inexact = mpfr_round (y, x);
- else if (r == GMP_RNDZ)
- inexact = mpfr_trunc (y, x);
- else if (r == GMP_RNDU)
- inexact = mpfr_ceil (y, x);
- else /* r = GMP_RNDD */
- inexact = mpfr_floor (y, x);
- if (mpfr_sub (t, y, x, GMP_RNDN))
- {
- printf ("Error: subtraction should be exact\n");
- exit (1);
- }
- sign_t = mpfr_cmp_ui (t, 0);
- if (((inexact == 0) && (sign_t != 0)) ||
- ((inexact < 0) && (sign_t >= 0)) ||
- ((inexact > 0) && (sign_t <= 0)))
- {
- printf ("Wrong inexact flag\n");
- exit (1);
- }
- }
+ mpfr_set_prec (v, p);
+ for (r = 0; r < 4; r++)
+ for (trint = 0; trint < 2; trint++)
+ {
+ if (trint)
+ inexact = mpfr_rint (y, x, r);
+ else if (r == GMP_RNDN)
+ inexact = mpfr_round (y, x);
+ else if (r == GMP_RNDZ)
+ inexact = mpfr_trunc (y, x);
+ else if (r == GMP_RNDU)
+ inexact = mpfr_ceil (y, x);
+ else /* r = GMP_RNDD */
+ inexact = mpfr_floor (y, x);
+ if (mpfr_sub (t, y, x, GMP_RNDN))
+ err ("subtraction 1 should be exact",
+ s, x, y, p, r, trint, inexact);
+ sign_t = mpfr_cmp_ui (t, 0);
+ if (((inexact == 0) && (sign_t != 0)) ||
+ ((inexact < 0) && (sign_t >= 0)) ||
+ ((inexact > 0) && (sign_t <= 0)))
+ err ("wrong inexact flag", s, x, y, p, r, trint, inexact);
+ if (inexact == 0)
+ continue; /* end of the test for exact results */
+
+ if (((r == GMP_RNDD || (r == GMP_RNDZ && MPFR_SIGN (x) > 0))
+ && inexact > 0) ||
+ ((r == GMP_RNDU || (r == GMP_RNDZ && MPFR_SIGN (x) < 0))
+ && inexact < 0))
+ err ("wrong rounding direction",
+ s, x, y, p, r, trint, inexact);
+ if (inexact < 0)
+ {
+ mpfr_add_ui (v, y, 1, GMP_RNDU);
+ if (mpfr_cmp (v, x) <= 0)
+ err ("representable integer between x and its "
+ "rounded value", s, x, y, p, r, trint, inexact);
+ }
+ else
+ {
+ mpfr_sub_ui (v, y, 1, GMP_RNDD);
+ if (mpfr_cmp (v, x) >= 0)
+ err ("representable integer between x and its "
+ "rounded value", s, x, y, p, r, trint, inexact);
+ }
+ if (r == GMP_RNDN)
+ {
+ int cmp;
+ if (mpfr_sub (u, v, x, GMP_RNDN))
+ err ("subtraction 2 should be exact",
+ s, x, y, p, r, trint, inexact);
+ cmp = mpfr_cmp_abs (t, u);
+ if (cmp > 0)
+ err ("faithful rounding, but not the nearest integer",
+ s, x, y, p, r, trint, inexact);
+ if (cmp < 0)
+ continue;
+ /* |t| = |u|: x is the middle of two consecutive
+ representable integers. */
+ if (trint)
+ {
+ /* halfway case for mpfr_rint in GMP_RNDN rounding
+ mode: round to an even integer or mantissa. */
+ mpfr_div_2ui (y, y, 1, GMP_RNDZ);
+ if (!mpfr_integer_p (y))
+ err ("halfway case for mpfr_rint, result isn't an"
+ " even integer", s, x, y, p, r, trint, inexact);
+ /* If floor(x) and ceil(x) aren't both representable
+ integers, the mantissa must be even. */
+ mpfr_sub (v, v, y, GMP_RNDN);
+ mpfr_abs (v, v, GMP_RNDN);
+ if (mpfr_cmp_ui (v, 1) != 0)
+ {
+ mpfr_div_2si (y, y, MPFR_EXP (y) - MPFR_PREC (y)
+ + 1, GMP_RNDN);
+ if (!mpfr_integer_p (y))
+ err ("halfway case for mpfr_rint, mantissa isn't"
+ " even", s, x, y, p, r, trint, inexact);
+ }
+ }
+ else
+ { /* halfway case for mpfr_round: x must have been
+ rounded away from zero. */
+ if ((MPFR_SIGN (x) > 0 && inexact < 0) ||
+ (MPFR_SIGN (x) < 0 && inexact > 0))
+ err ("halfway case for mpfr_round, bad rounding"
+ " direction", s, x, y, p, r, trint, inexact);
+ }
+ }
+ }
}
}
mpfr_clear (x);
mpfr_clear (y);
mpz_clear (z);
mpfr_clear (t);
+ mpfr_clear (u);
+ mpfr_clear (v);
+
+ /* TODO: add hardcoded tests */
+#if __STDC_VERSION__ >= 199901L
+ if (argc > 1 && strcmp (argv[1], "-s") == 0)
+ test_against_libc ();
+#endif
tests_end_mpfr ();
return 0;