tcan_round.c revision 1.1.1.4 1 /* Test file for mpfr_can_round and mpfr_round_p.
2
3 Copyright 1999, 2001-2018 Free Software Foundation, Inc.
4 Contributed by the AriC and Caramba projects, INRIA.
5
6 This file is part of the GNU MPFR Library.
7
8 The GNU MPFR Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12
13 The GNU MPFR Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
20 http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22
23 #include "mpfr-test.h"
24
25 /* Simple cases where err - prec is large enough.
26 One can get failures as a consequence of r9883. */
27 static void
28 test_simple (void)
29 {
30 int t[4] = { 2, 3, -2, -3 }; /* test powers of 2 and non-powers of 2 */
31 int i;
32 int r1, r2;
33
34 for (i = 0; i < 4; i++)
35 RND_LOOP (r1)
36 RND_LOOP (r2)
37 {
38 mpfr_t b;
39 int p, err, prec, inex, c;
40
41 if (r2 == MPFR_RNDF)
42 continue;
43 p = 12 + (randlimb() % (2 * GMP_NUMB_BITS));
44 err = p - 3;
45 prec = 4;
46 mpfr_init2 (b, p);
47 inex = mpfr_set_si (b, t[i], MPFR_RNDN);
48 MPFR_ASSERTN (inex == 0);
49 c = mpfr_can_round (b, err, (mpfr_rnd_t) r1, (mpfr_rnd_t) r2, prec);
50 /* If r1 == r2, we can round.
51 Note: For r1, RNDF is equivalent to RNDN.
52 TODO: complete this test for r1 != r2. */
53 if ((r1 == MPFR_RNDF ? MPFR_RNDN : r1) == r2 && !c)
54 {
55 printf ("Error in test_simple for i=%d,"
56 " err=%d r1=%s, r2=%s, p=%d\n", i, err,
57 mpfr_print_rnd_mode ((mpfr_rnd_t) r1),
58 mpfr_print_rnd_mode ((mpfr_rnd_t) r2), p);
59 printf ("b="); mpfr_dump (b);
60 exit (1);
61 }
62 mpfr_clear (b);
63 }
64 }
65
66 #define MAX_LIMB_SIZE 100
67
68 static void
69 check_round_p (void)
70 {
71 mp_limb_t buf[MAX_LIMB_SIZE];
72 mp_size_t n, i;
73 mpfr_prec_t p;
74 mpfr_exp_t err;
75 int r1, r2;
76
77 for (n = 2 ; n <= MAX_LIMB_SIZE ; n++)
78 {
79 /* avoid mpn_random which leaks memory */
80 for (i = 0; i < n; i++)
81 buf[i] = randlimb ();
82 /* force the number to be normalized */
83 buf[n - 1] |= MPFR_LIMB_HIGHBIT;
84 p = randlimb() % ((n-1) * GMP_NUMB_BITS) + MPFR_PREC_MIN;
85 err = p + randlimb () % GMP_NUMB_BITS;
86 r1 = mpfr_round_p (buf, n, err, p);
87 r2 = mpfr_can_round_raw (buf, n, MPFR_SIGN_POS, err,
88 MPFR_RNDN, MPFR_RNDZ, p);
89 if (r1 != r2)
90 {
91 printf ("mpfr_round_p(%d) != mpfr_can_round(%d)!\n"
92 "bn = %ld, err0 = %ld, prec = %lu\nbp = ",
93 r1, r2, n, (long) err, (unsigned long) p);
94 #ifndef MPFR_USE_MINI_GMP
95 gmp_printf ("%NX\n", buf, n);
96 #endif
97 exit (1);
98 }
99 }
100 }
101
102 /* check x=2^i with precision px, error at most 1, and target precision prec */
103 static void
104 test_pow2 (mpfr_exp_t i, mpfr_prec_t px, mpfr_rnd_t r1, mpfr_rnd_t r2,
105 mpfr_prec_t prec)
106 {
107 mpfr_t x;
108 int b, expected_b, b2;
109
110 mpfr_init2 (x, px);
111 mpfr_set_ui_2exp (x, 1, i, MPFR_RNDN);
112 /* for mpfr_can_round, r1=RNDF is equivalent to r1=RNDN (the sign of the
113 error is not known) */
114 b = !!mpfr_can_round (x, i+1, r1, r2, prec);
115 /* Note: If mpfr_can_round succeeds for both
116 (r1,r2) = (MPFR_RNDD,MPFR_RNDN) and
117 (r1,r2) = (MPFR_RNDU,MPFR_RNDN), then it should succeed for
118 (r1,r2) = (MPFR_RNDN,MPFR_RNDN). So, the condition on prec below
119 for r1 = MPFR_RNDN should be the most restrictive between those
120 for r1 = any directed rounding mode.
121 For r1 like MPFR_RNDA, the unrounded, unknown number may be anyone
122 in [2^i-1,i]. As both 2^i-1 and 2^i fit on i bits, one cannot round
123 in any precision >= i bits, hence the condition prec < i; prec = i-1
124 will work here for r2 = MPFR_RNDN thanks to the even-rounding rule
125 (and also with rounding ties away from zero). */
126 expected_b =
127 MPFR_IS_LIKE_RNDD (r1, MPFR_SIGN_POS) ?
128 (MPFR_IS_LIKE_RNDU (r2, MPFR_SIGN_POS) ? 0 : prec <= i) :
129 MPFR_IS_LIKE_RNDU (r1, MPFR_SIGN_POS) ?
130 (MPFR_IS_LIKE_RNDD (r2, MPFR_SIGN_POS) ? 0 : prec < i) :
131 (r2 != MPFR_RNDN ? 0 : prec < i);
132 if (b != expected_b)
133 {
134 printf ("Error for x=2^%d, px=%lu, err=%d, r1=%s, r2=%s, prec=%d\n",
135 (int) i, (unsigned long) px, (int) i + 1,
136 mpfr_print_rnd_mode (r1), mpfr_print_rnd_mode (r2), (int) prec);
137 printf ("Expected %d, got %d\n", expected_b, b);
138 exit (1);
139 }
140
141 if (r1 == MPFR_RNDN && r2 == MPFR_RNDZ)
142 {
143 /* Similar test to the one done in src/round_p.c
144 for MPFR_WANT_ASSERT >= 2. */
145 b2 = !!mpfr_round_p (MPFR_MANT(x), MPFR_LIMB_SIZE(x), i+1, prec);
146 if (b2 != b)
147 {
148 printf ("Error for x=2^%d, px=%lu, err=%d, prec=%d\n",
149 (int) i, (unsigned long) px, (int) i + 1, (int) prec);
150 printf ("mpfr_can_round gave %d, mpfr_round_p gave %d\n", b, b2);
151 exit (1);
152 }
153 }
154
155 mpfr_clear (x);
156 }
157
158 static void
159 check_can_round (void)
160 {
161 mpfr_t x, xinf, xsup, yinf, ysup;
162 int precx, precy, err;
163 int rnd1, rnd2;
164 int i, u[3] = { 0, 1, 256 };
165 int inex;
166 int expected, got;
167
168 mpfr_inits2 (4 * GMP_NUMB_BITS, x, xinf, xsup, yinf, ysup, (mpfr_ptr) 0);
169
170 for (precx = 3 * GMP_NUMB_BITS - 3; precx <= 3 * GMP_NUMB_BITS + 3; precx++)
171 {
172 mpfr_set_prec (x, precx);
173 for (precy = precx - 4; precy <= precx + 4; precy++)
174 {
175 mpfr_set_prec (yinf, precy);
176 mpfr_set_prec (ysup, precy);
177
178 for (i = 0; i <= 3; i++)
179 {
180 if (i <= 2)
181 {
182 /* Test x = 2^(precx - 1) + u */
183 mpfr_set_ui_2exp (x, 1, precx - 1, MPFR_RNDN);
184 mpfr_add_ui (x, x, u[i], MPFR_RNDN);
185 }
186 else
187 {
188 /* Test x = 2^precx - 1 */
189 mpfr_set_ui_2exp (x, 1, precx, MPFR_RNDN);
190 mpfr_sub_ui (x, x, 1, MPFR_RNDN);
191 }
192 MPFR_ASSERTN (mpfr_get_exp (x) == precx);
193
194 for (err = precy; err <= precy + 3; err++)
195 {
196 mpfr_set_ui_2exp (xinf, 1, precx - err, MPFR_RNDN);
197 inex = mpfr_add (xsup, x, xinf, MPFR_RNDN);
198 MPFR_ASSERTN (inex == 0);
199 inex = mpfr_sub (xinf, x, xinf, MPFR_RNDN);
200 MPFR_ASSERTN (inex == 0);
201 RND_LOOP (rnd1)
202 RND_LOOP (rnd2)
203 {
204 if (rnd2 == MPFR_RNDF)
205 continue;
206 mpfr_set (yinf, MPFR_IS_LIKE_RNDD (rnd1, 1) ?
207 x : xinf, (mpfr_rnd_t) rnd2);
208 mpfr_set (ysup, MPFR_IS_LIKE_RNDU (rnd1, 1) ?
209 x : xsup, (mpfr_rnd_t) rnd2);
210 expected = !! mpfr_equal_p (yinf, ysup);
211 got = !! mpfr_can_round (x, err, (mpfr_rnd_t) rnd1,
212 (mpfr_rnd_t) rnd2, precy);
213 if (got != expected)
214 {
215 printf ("Error in check_can_round on:\n"
216 "precx=%d, precy=%d, i=%d, err=%d, "
217 "rnd1=%s, rnd2=%s: got %d\n",
218 precx, precy, i, err,
219 mpfr_print_rnd_mode ((mpfr_rnd_t) rnd1),
220 mpfr_print_rnd_mode ((mpfr_rnd_t) rnd2),
221 got);
222 printf ("x="); mpfr_dump (x);
223 exit (1);
224 }
225 }
226 }
227 }
228 }
229 }
230
231 mpfr_clears (x, xinf, xsup, yinf, ysup, (mpfr_ptr) 0);
232 }
233
234 int
235 main (void)
236 {
237 mpfr_t x;
238 mpfr_prec_t i, j, k;
239 int r1, r2;
240 int n;
241
242 tests_start_mpfr ();
243
244 test_simple ();
245
246 /* checks that rounds to nearest sets the last
247 bit to zero in case of equal distance */
248 mpfr_init2 (x, 59);
249 mpfr_set_str_binary (x, "-0.10010001010111000011110010111010111110000000111101100111111E663");
250 if (mpfr_can_round (x, 54, MPFR_RNDZ, MPFR_RNDZ, 53))
251 {
252 printf ("Error (1) in mpfr_can_round\n");
253 exit (1);
254 }
255
256 mpfr_set_str_binary (x, "-Inf");
257 if (mpfr_can_round (x, 2000, MPFR_RNDZ, MPFR_RNDZ, 2000))
258 {
259 printf ("Error (2) in mpfr_can_round\n");
260 exit (1);
261 }
262
263 mpfr_set_prec (x, 64);
264 mpfr_set_str_binary (x, "0.1011001000011110000110000110001111101011000010001110011000000000");
265 if (mpfr_can_round (x, 65, MPFR_RNDN, MPFR_RNDN, 54))
266 {
267 printf ("Error (3) in mpfr_can_round\n");
268 exit (1);
269 }
270
271 mpfr_set_prec (x, 137);
272 mpfr_set_str_binary (x, "-0.10111001101001010110011000110100111010011101101010010100101100001110000100111111011101010110001010111100100101110111100001000010000000000E-97");
273 if (! mpfr_can_round (x, 132, MPFR_RNDU, MPFR_RNDZ, 128))
274 {
275 printf ("Error (4) in mpfr_can_round\n");
276 exit (1);
277 }
278
279 /* in the following, we can round but cannot determine the inexact flag */
280 mpfr_set_prec (x, 86);
281 mpfr_set_str_binary (x, "-0.11100100010011001111011010100111101010011000000000000000000000000000000000000000000000E-80");
282 if (! mpfr_can_round (x, 81, MPFR_RNDU, MPFR_RNDZ, 44))
283 {
284 printf ("Error (5) in mpfr_can_round\n");
285 exit (1);
286 }
287
288 mpfr_set_prec (x, 62);
289 mpfr_set_str (x, "0.ff4ca619c76ba69", 16, MPFR_RNDZ);
290 for (i = 30; i < 99; i++)
291 for (j = 30; j < 99; j++)
292 RND_LOOP (r1)
293 RND_LOOP (r2)
294 if (r2 != MPFR_RNDF)
295 {
296 /* test for assertions */
297 mpfr_can_round (x, i, (mpfr_rnd_t) r1, (mpfr_rnd_t) r2, j);
298 }
299
300 test_pow2 (32, 32, MPFR_RNDN, MPFR_RNDN, 32);
301 test_pow2 (174, 174, MPFR_RNDN, MPFR_RNDN, 174);
302 test_pow2 (174, 174, MPFR_RNDU, MPFR_RNDN, 174);
303 test_pow2 (176, 129, MPFR_RNDU, MPFR_RNDU, 174);
304 test_pow2 (176, 2, MPFR_RNDZ, MPFR_RNDZ, 174);
305 test_pow2 (176, 2, MPFR_RNDU, MPFR_RNDU, 176);
306
307 /* Tests for x = 2^i (E(x) = i+1) with error at most 1 = 2^0. */
308 for (n = 0; n < 100; n++)
309 {
310 i = (randlimb() % 200) + 4;
311 for (j = i - 2; j < i + 2; j++)
312 RND_LOOP (r1)
313 RND_LOOP (r2)
314 if (r2 != MPFR_RNDF)
315 for (k = MPFR_PREC_MIN; k <= i + 2; k++)
316 test_pow2 (i, k, (mpfr_rnd_t) r1, (mpfr_rnd_t) r2, j);
317 }
318
319 mpfr_clear (x);
320
321 check_can_round ();
322
323 check_round_p ();
324
325 tests_end_mpfr ();
326 return 0;
327 }
328