xref: /netbsd-src/external/lgpl3/mpfr/dist/tests/tpow_all.c (revision ba125506a622fe649968631a56eba5d42ff57863)
1 /* Test file for the various power functions
2 
3 Copyright 2008-2023 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 https://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 /* Note: some tests of the other tpow* test files could be moved there.
24    The main goal of this test file is to test _all_ the power functions
25    on special values, to make sure that they are consistent and give the
26    expected result, in particular because such special cases are handled
27    in different ways in each function. */
28 
29 /* Execute with at least an argument to report all the errors found by
30    comparisons. */
31 
32 #include "mpfr-test.h"
33 
34 /* Behavior of cmpres (called by test_others):
35  *   0: stop as soon as an error is found.
36  *   1: report all errors found by test_others.
37  *  -1: the 1 is changed to this value as soon as an error has been found.
38  */
39 static int all_cmpres_errors;
40 
41 /* Non-zero when extended exponent range */
42 static int ext = 0;
43 
44 static const char *val[] =
45   { "min", "min+", "max", "@NaN@", "-@Inf@", "-4", "-3", "-2", "-1.5",
46     "-1", "-0.5", "-0", "0", "0.5", "1", "1.5", "2", "3", "4", "@Inf@" };
47 
48 static void
err(const char * s,int i,int j,int rnd,mpfr_srcptr z,int inex)49 err (const char *s, int i, int j, int rnd, mpfr_srcptr z, int inex)
50 {
51   puts (s);
52   if (ext)
53     puts ("extended exponent range");
54   printf ("x = %s, y = %s, %s\n", val[i], val[j],
55           mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
56   printf ("z = ");
57   mpfr_out_str (stdout, 10, 0, z, MPFR_RNDN);
58   printf ("\ninex = %d\n", inex);
59   exit (1);
60 }
61 
62 /* Arguments:
63  *   spx: non-zero if px is a stringm zero if px is a MPFR number.
64  *   px: value of x (string or MPFR number).
65  *   sy: value of y (string).
66  *   rnd: rounding mode.
67  *   z1: expected result (null pointer if unknown pure FP value).
68  *   inex1: expected ternary value (if z1 is not a null pointer).
69  *   z2: computed result.
70  *   inex2: computed ternary value.
71  *   flags1: expected flags (computed flags in __gmpfr_flags).
72  *   s1, s2: strings about the context.
73  */
74 static void
cmpres(int spx,const void * px,const char * sy,mpfr_rnd_t rnd,mpfr_srcptr z1,int inex1,mpfr_srcptr z2,int inex2,unsigned int flags1,const char * s1,const char * s2)75 cmpres (int spx, const void *px, const char *sy, mpfr_rnd_t rnd,
76         mpfr_srcptr z1, int inex1, mpfr_srcptr z2, int inex2,
77         unsigned int flags1, const char *s1, const char *s2)
78 {
79   unsigned int flags2 = __gmpfr_flags;
80 
81   if (flags1 == flags2)
82     {
83       /* Note: the test on the sign of z1 and z2 is needed
84          in case they are both zeros. */
85       if (z1 == NULL)
86         {
87           if (MPFR_IS_PURE_FP (z2))
88             return;
89         }
90       else if (SAME_SIGN (inex1, inex2) && SAME_VAL (z1, z2))
91         return;
92     }
93 
94   printf ("Error in %s\nwith %s%s\nx = ", s1, s2,
95           ext ? ", extended exponent range" : "");
96   if (spx)
97     printf ("%s, ", (char *) px);
98   else
99     {
100       mpfr_out_str (stdout, 16, 0, (mpfr_ptr) px, MPFR_RNDN);
101       puts (",");
102     }
103   printf ("y = %s, %s\n", sy, mpfr_print_rnd_mode (rnd));
104   printf ("Expected ");
105   if (z1 == NULL)
106     {
107       printf ("pure FP value, flags =");
108       flags_out (flags1);
109     }
110   else
111     {
112       mpfr_out_str (stdout, 16, 0, z1, MPFR_RNDN);
113       printf (", inex = %d,\n         flags =", VSIGN (inex1));
114       flags_out (flags1);
115     }
116   printf ("Got      ");
117   mpfr_out_str (stdout, 16, 0, z2, MPFR_RNDN);
118   printf (", inex = %d,\n         flags =", VSIGN (inex2));
119   flags_out (flags2);
120   if (all_cmpres_errors != 0)
121     all_cmpres_errors = -1;
122   else
123     exit (1);
124 }
125 
126 static int
is_odd(mpfr_srcptr x)127 is_odd (mpfr_srcptr x)
128 {
129   /* works only with the values from val[] */
130   return mpfr_integer_p (x) && mpfr_fits_slong_p (x, MPFR_RNDN) &&
131     (mpfr_get_si (x, MPFR_RNDN) & 1);
132 }
133 
134 /* Compare the result (z1,inex1) of mpfr_pow with all flags cleared
135    with those of mpfr_pow with all flags set and of the other power
136    functions. Arguments x and y are the input values; sx and sy are
137    their string representations (sx may be null); rnd contains the
138    rounding mode; s is a string containing the function that called
139    test_others. */
140 static void
test_others(const void * sx,const char * sy,mpfr_rnd_t rnd,mpfr_srcptr x,mpfr_srcptr y,mpfr_srcptr z1,int inex1,unsigned int flags,const char * s)141 test_others (const void *sx, const char *sy, mpfr_rnd_t rnd,
142              mpfr_srcptr x, mpfr_srcptr y, mpfr_srcptr z1,
143              int inex1, unsigned int flags, const char *s)
144 {
145   mpfr_t z2;
146   int inex2;
147   int spx = sx != NULL;
148 
149   if (!spx)
150     sx = x;
151 
152   mpfr_init2 (z2, mpfr_get_prec (z1));
153 
154   __gmpfr_flags = MPFR_FLAGS_ALL;
155   inex2 = mpfr_pow (z2, x, y, rnd);
156   cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL,
157           s, "mpfr_pow, flags set");
158 
159   /* If y is an integer that fits in an unsigned long and is not -0,
160      we can test mpfr_pow_ui. */
161   if (MPFR_IS_POS (y) && mpfr_integer_p (y) &&
162       mpfr_fits_ulong_p (y, MPFR_RNDN))
163     {
164       unsigned long yy = mpfr_get_ui (y, MPFR_RNDN);
165 
166       mpfr_clear_flags ();
167       inex2 = mpfr_pow_ui (z2, x, yy, rnd);
168       cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags,
169               s, "mpfr_pow_ui, flags cleared");
170       __gmpfr_flags = MPFR_FLAGS_ALL;
171       inex2 = mpfr_pow_ui (z2, x, yy, rnd);
172       cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL,
173               s, "mpfr_pow_ui, flags set");
174 
175       /* If x is an integer that fits in an unsigned long and is not -0,
176          we can also test mpfr_ui_pow_ui. */
177       if (MPFR_IS_POS (x) && mpfr_integer_p (x) &&
178           mpfr_fits_ulong_p (x, MPFR_RNDN))
179         {
180           unsigned long xx = mpfr_get_ui (x, MPFR_RNDN);
181 
182           mpfr_clear_flags ();
183           inex2 = mpfr_ui_pow_ui (z2, xx, yy, rnd);
184           cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags,
185                   s, "mpfr_ui_pow_ui, flags cleared");
186           __gmpfr_flags = MPFR_FLAGS_ALL;
187           inex2 = mpfr_ui_pow_ui (z2, xx, yy, rnd);
188           cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL,
189                   s, "mpfr_ui_pow_ui, flags set");
190         }
191     }
192 
193   /* If y is an integer but not -0 and not huge, we can test mpfr_pow_z,
194      and possibly mpfr_pow_si (and possibly mpfr_ui_div). */
195   if (MPFR_IS_ZERO (y) ? MPFR_IS_POS (y) :
196       (mpfr_integer_p (y) && MPFR_GET_EXP (y) < 256))
197     {
198       mpz_t yyy;
199 
200       /* If y fits in a long, we can test mpfr_pow_si. */
201       if (mpfr_fits_slong_p (y, MPFR_RNDN))
202         {
203           long yy = mpfr_get_si (y, MPFR_RNDN);
204 
205           mpfr_clear_flags ();
206           inex2 = mpfr_pow_si (z2, x, yy, rnd);
207           cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags,
208                   s, "mpfr_pow_si, flags cleared");
209           __gmpfr_flags = MPFR_FLAGS_ALL;
210           inex2 = mpfr_pow_si (z2, x, yy, rnd);
211           cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL,
212                   s, "mpfr_pow_si, flags set");
213 
214           /* If y = -1, we can test mpfr_ui_div. */
215           if (yy == -1)
216             {
217               mpfr_clear_flags ();
218               inex2 = mpfr_ui_div (z2, 1, x, rnd);
219               cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags,
220                       s, "mpfr_ui_div, flags cleared");
221               __gmpfr_flags = MPFR_FLAGS_ALL;
222               inex2 = mpfr_ui_div (z2, 1, x, rnd);
223               cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL,
224                       s, "mpfr_ui_div, flags set");
225             }
226 
227           /* If y = 2, we can test mpfr_sqr. */
228           if (yy == 2)
229             {
230               mpfr_clear_flags ();
231               inex2 = mpfr_sqr (z2, x, rnd);
232               cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags,
233                       s, "mpfr_sqr, flags cleared");
234               __gmpfr_flags = MPFR_FLAGS_ALL;
235               inex2 = mpfr_sqr (z2, x, rnd);
236               cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL,
237                       s, "mpfr_sqr, flags set");
238             }
239         }
240 
241       /* Test mpfr_pow_z. */
242       mpz_init (yyy);
243       mpfr_get_z (yyy, y, MPFR_RNDN);
244       mpfr_clear_flags ();
245       inex2 = mpfr_pow_z (z2, x, yyy, rnd);
246       cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags,
247               s, "mpfr_pow_z, flags cleared");
248       __gmpfr_flags = MPFR_FLAGS_ALL;
249       inex2 = mpfr_pow_z (z2, x, yyy, rnd);
250       cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL,
251               s, "mpfr_pow_z, flags set");
252       mpz_clear (yyy);
253     }
254 
255   /* If y = 0.5, we can test mpfr_sqrt, except if x is -0 or -Inf (because
256      the rule for mpfr_pow on these special values is different). */
257   if (MPFR_IS_PURE_FP (y) && mpfr_cmp_str1 (y, "0.5") == 0 &&
258       ! ((MPFR_IS_ZERO (x) || MPFR_IS_INF (x)) && MPFR_IS_NEG (x)))
259     {
260       mpfr_clear_flags ();
261       inex2 = mpfr_sqrt (z2, x, rnd);
262       cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags,
263               s, "mpfr_sqrt, flags cleared");
264       __gmpfr_flags = MPFR_FLAGS_ALL;
265       inex2 = mpfr_sqrt (z2, x, rnd);
266       cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL,
267               s, "mpfr_sqrt, flags set");
268     }
269 
270   /* If y = -0.5, we can test mpfr_rec_sqrt, except if x = -Inf
271      (because the rule for mpfr_pow on -Inf is different). */
272   if (MPFR_IS_PURE_FP (y) && mpfr_cmp_str1 (y, "-0.5") == 0 &&
273       ! (MPFR_IS_INF (x) && MPFR_IS_NEG (x)))
274     {
275       mpfr_clear_flags ();
276       inex2 = mpfr_rec_sqrt (z2, x, rnd);
277       cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags,
278               s, "mpfr_rec_sqrt, flags cleared");
279       __gmpfr_flags = MPFR_FLAGS_ALL;
280       inex2 = mpfr_rec_sqrt (z2, x, rnd);
281       cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL,
282               s, "mpfr_rec_sqrt, flags set");
283     }
284 
285   /* If x is an integer that fits in an unsigned long and is not -0,
286      we can test mpfr_ui_pow. */
287   if (MPFR_IS_POS (x) && mpfr_integer_p (x) &&
288       mpfr_fits_ulong_p (x, MPFR_RNDN))
289     {
290       unsigned long xx = mpfr_get_ui (x, MPFR_RNDN);
291 
292       mpfr_clear_flags ();
293       inex2 = mpfr_ui_pow (z2, xx, y, rnd);
294       cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags,
295               s, "mpfr_ui_pow, flags cleared");
296       __gmpfr_flags = MPFR_FLAGS_ALL;
297       inex2 = mpfr_ui_pow (z2, xx, y, rnd);
298       cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL,
299               s, "mpfr_ui_pow, flags set");
300 
301       /* If x = 2, we can test mpfr_exp2. */
302       if (xx == 2)
303         {
304           mpfr_clear_flags ();
305           inex2 = mpfr_exp2 (z2, y, rnd);
306           cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags,
307                   s, "mpfr_exp2, flags cleared");
308           __gmpfr_flags = MPFR_FLAGS_ALL;
309           inex2 = mpfr_exp2 (z2, y, rnd);
310           cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL,
311                   s, "mpfr_exp2, flags set");
312         }
313 
314       /* If x = 10, we can test mpfr_exp10. */
315       if (xx == 10)
316         {
317           mpfr_clear_flags ();
318           inex2 = mpfr_exp10 (z2, y, rnd);
319           cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, flags,
320                   s, "mpfr_exp10, flags cleared");
321           __gmpfr_flags = MPFR_FLAGS_ALL;
322           inex2 = mpfr_exp10 (z2, y, rnd);
323           cmpres (spx, sx, sy, rnd, z1, inex1, z2, inex2, MPFR_FLAGS_ALL,
324                   s, "mpfr_exp10, flags set");
325         }
326     }
327 
328   mpfr_clear (z2);
329 }
330 
331 static int
my_setstr(mpfr_ptr t,const char * s)332 my_setstr (mpfr_ptr t, const char *s)
333 {
334   if (strcmp (s, "min") == 0)
335     {
336       mpfr_setmin (t, mpfr_get_emin ());
337       MPFR_SET_POS (t);
338       return 0;
339     }
340   if (strcmp (s, "min+") == 0)
341     {
342       mpfr_setmin (t, mpfr_get_emin ());
343       MPFR_SET_POS (t);
344       mpfr_nextabove (t);
345       return 0;
346     }
347   if (strcmp (s, "max") == 0)
348     {
349       mpfr_setmax (t, mpfr_get_emax ());
350       MPFR_SET_POS (t);
351       return 0;
352     }
353   return mpfr_set_str (t, s, 10, MPFR_RNDN);
354 }
355 
356 static void
tst(void)357 tst (void)
358 {
359   int sv = numberof (val);
360   int i, j;
361   int rnd;
362   mpfr_t x, y, z, tmp;
363 
364   mpfr_inits2 (53, x, y, z, tmp, (mpfr_ptr) 0);
365 
366   for (i = 0; i < sv; i++)
367     for (j = 0; j < sv; j++)
368       RND_LOOP_NO_RNDF (rnd)
369         {
370           int exact, inex;
371           unsigned int flags;
372 
373           if (my_setstr (x, val[i]) || my_setstr (y, val[j]))
374             {
375               printf ("internal error for (%d,%d,%d)\n", i, j, rnd);
376               exit (1);
377             }
378           mpfr_clear_flags ();
379           inex = mpfr_pow (z, x, y, (mpfr_rnd_t) rnd);
380           flags = __gmpfr_flags;
381           if (! MPFR_IS_NAN (z) && mpfr_nanflag_p ())
382             err ("got NaN flag without NaN value", i, j, rnd, z, inex);
383           if (MPFR_IS_NAN (z) && ! mpfr_nanflag_p ())
384             err ("got NaN value without NaN flag", i, j, rnd, z, inex);
385           if (inex != 0 && ! mpfr_inexflag_p ())
386             err ("got non-zero ternary value without inexact flag",
387                  i, j, rnd, z, inex);
388           if (inex == 0 && mpfr_inexflag_p ())
389             err ("got null ternary value with inexact flag",
390                  i, j, rnd, z, inex);
391           if (i >= 3 && j >= 3)
392             {
393               if (mpfr_underflow_p ())
394                 err ("got underflow", i, j, rnd, z, inex);
395               if (mpfr_overflow_p ())
396                 err ("got overflow", i, j, rnd, z, inex);
397               exact = MPFR_IS_SINGULAR (z) ||
398                 (mpfr_mul_2ui (tmp, z, 16, MPFR_RNDN), mpfr_integer_p (tmp));
399               if (exact && inex != 0)
400                 err ("got exact value with ternary flag different from 0",
401                      i, j, rnd, z, inex);
402               if (! exact && inex == 0)
403                 err ("got inexact value with ternary flag equal to 0",
404                      i, j, rnd, z, inex);
405             }
406           if (MPFR_IS_ZERO (x) && ! MPFR_IS_NAN (y) && MPFR_NOTZERO (y))
407             {
408               if (MPFR_IS_NEG (y) && ! MPFR_IS_INF (z))
409                 err ("expected an infinity", i, j, rnd, z, inex);
410               if (MPFR_IS_POS (y) && ! MPFR_IS_ZERO (z))
411                 err ("expected a zero", i, j, rnd, z, inex);
412               if ((MPFR_IS_NEG (x) && is_odd (y)) ^ MPFR_IS_NEG (z))
413                 err ("wrong sign", i, j, rnd, z, inex);
414             }
415           if (! MPFR_IS_NAN (x) && mpfr_cmp_si (x, -1) == 0)
416             {
417               /* x = -1 */
418               if (! (MPFR_IS_INF (y) || mpfr_integer_p (y)) &&
419                   ! MPFR_IS_NAN (z))
420                 err ("expected NaN", i, j, rnd, z, inex);
421               if ((MPFR_IS_INF (y) || (mpfr_integer_p (y) && ! is_odd (y)))
422                   && ! mpfr_equal_p (z, __gmpfr_one))
423                 err ("expected 1", i, j, rnd, z, inex);
424               if (is_odd (y) &&
425                   (MPFR_IS_NAN (z) || mpfr_cmp_si (z, -1) != 0))
426                 err ("expected -1", i, j, rnd, z, inex);
427             }
428           if ((mpfr_equal_p (x, __gmpfr_one) || MPFR_IS_ZERO (y)) &&
429               ! mpfr_equal_p (z, __gmpfr_one))
430             err ("expected 1", i, j, rnd, z, inex);
431           if (MPFR_IS_PURE_FP (x) && MPFR_IS_NEG (x) &&
432               MPFR_IS_FP (y) && ! mpfr_integer_p (y) &&
433               ! MPFR_IS_NAN (z))
434             err ("expected NaN", i, j, rnd, z, inex);
435           if (MPFR_IS_INF (y) && MPFR_NOTZERO (x))
436             {
437               int cmpabs1 = mpfr_cmpabs (x, __gmpfr_one);
438 
439               if ((MPFR_IS_NEG (y) ? (cmpabs1 < 0) : (cmpabs1 > 0)) &&
440                   ! (MPFR_IS_POS (z) && MPFR_IS_INF (z)))
441                 err ("expected +Inf", i, j, rnd, z, inex);
442               if ((MPFR_IS_NEG (y) ? (cmpabs1 > 0) : (cmpabs1 < 0)) &&
443                   ! (MPFR_IS_POS (z) && MPFR_IS_ZERO (z)))
444                 err ("expected +0", i, j, rnd, z, inex);
445             }
446           if (MPFR_IS_INF (x) && ! MPFR_IS_NAN (y) && MPFR_NOTZERO (y))
447             {
448               if (MPFR_IS_POS (y) && ! MPFR_IS_INF (z))
449                 err ("expected an infinity", i, j, rnd, z, inex);
450               if (MPFR_IS_NEG (y) && ! MPFR_IS_ZERO (z))
451                 err ("expected a zero", i, j, rnd, z, inex);
452               if ((MPFR_IS_NEG (x) && is_odd (y)) ^ MPFR_IS_NEG (z))
453                 err ("wrong sign", i, j, rnd, z, inex);
454             }
455           test_others (val[i], val[j], (mpfr_rnd_t) rnd, x, y, z, inex, flags,
456                        "tst");
457         }
458   mpfr_clears (x, y, z, tmp, (mpfr_ptr) 0);
459 }
460 
461 static void
underflow_up1(void)462 underflow_up1 (void)
463 {
464   mpfr_t delta, x, y, z, z0;
465   mpfr_exp_t n;
466   int inex;
467   int rnd;
468   int i;
469 
470   n = mpfr_get_emin ();
471   if (n < LONG_MIN)
472     return;
473 
474   mpfr_init2 (delta, 2);
475   inex = mpfr_set_ui_2exp (delta, 1, -2, MPFR_RNDN);
476   MPFR_ASSERTN (inex == 0);
477 
478   mpfr_init2 (x, 8);
479   inex = mpfr_set_ui (x, 2, MPFR_RNDN);
480   MPFR_ASSERTN (inex == 0);
481 
482   mpfr_init2 (y, sizeof (long) * CHAR_BIT + 4);
483   inex = mpfr_set_si (y, n, MPFR_RNDN);
484   MPFR_ASSERTN (inex == 0);
485 
486   mpfr_init2 (z0, 2);
487   mpfr_set_ui (z0, 0, MPFR_RNDN);
488 
489   mpfr_init2 (z, 32);
490 
491   for (i = 0; i <= 12; i++)
492     {
493       unsigned int flags = 0;
494       char sy[256];  /* larger than needed, for maintainability */
495 
496       /* Test 2^(emin - i/4).
497        * --> Underflow iff i > 4.
498        * --> Zero in MPFR_RNDN iff i >= 8.
499        */
500 
501       if (i != 0 && i != 4)
502         flags |= MPFR_FLAGS_INEXACT;
503       if (i > 4)
504         flags |= MPFR_FLAGS_UNDERFLOW;
505 
506       sprintf (sy, "emin - %d/4", i);
507 
508       RND_LOOP_NO_RNDF (rnd)
509         {
510           int zero;
511 
512           zero = (i > 4 && (rnd == MPFR_RNDZ || rnd == MPFR_RNDD)) ||
513             (i >= 8 && rnd == MPFR_RNDN);
514 
515           mpfr_clear_flags ();
516           inex = mpfr_pow (z, x, y, (mpfr_rnd_t) rnd);
517           cmpres (1, "2", sy, (mpfr_rnd_t) rnd, zero ? z0 : (mpfr_ptr) NULL,
518                   -1, z, inex, flags, "underflow_up1", "mpfr_pow");
519           test_others ("2", sy, (mpfr_rnd_t) rnd, x, y, z, inex, flags,
520                        "underflow_up1");
521         }
522 
523       inex = mpfr_sub (y, y, delta, MPFR_RNDN);
524       MPFR_ASSERTN (inex == 0);
525     }
526 
527   mpfr_clears (delta, x, y, z, z0, (mpfr_ptr) 0);
528 }
529 
530 /* With pow.c r5497, the following test fails on a 64-bit Linux machine
531  * due to a double-rounding problem when rescaling the result:
532  *   Error with underflow_up2 and extended exponent range
533  *   x = 7.fffffffffffffff0@-1,
534  *   y = 4611686018427387904, MPFR_RNDN
535  *   Expected 1.0000000000000000@-1152921504606846976, inex = 1, flags = 9
536  *   Got      0, inex = -1, flags = 9
537  * With pow_ui.c r5423, the following test fails on a 64-bit Linux machine
538  * as underflows and overflows are not handled correctly (the approximation
539  * error is ignored):
540  *   Error with mpfr_pow_ui, flags cleared
541  *   x = 7.fffffffffffffff0@-1,
542  *   y = 4611686018427387904, MPFR_RNDN
543  *   Expected 1.0000000000000000@-1152921504606846976, inex = 1, flags = 9
544  *   Got      0, inex = -1, flags = 9
545  */
546 static void
underflow_up2(void)547 underflow_up2 (void)
548 {
549   mpfr_t x, y, z, z0, eps;
550   mpfr_exp_t n;
551   int inex;
552   int rnd;
553 
554   n = 1 - mpfr_get_emin ();
555   MPFR_ASSERTN (n > 1);
556   if (n > ULONG_MAX)
557     return;
558 
559   mpfr_init2 (eps, 2);
560   mpfr_set_ui_2exp (eps, 1, -1, MPFR_RNDN);  /* 1/2 */
561   mpfr_div_ui (eps, eps, n, MPFR_RNDZ);      /* 1/(2n) rounded toward zero */
562 
563   mpfr_init2 (x, sizeof (unsigned long) * CHAR_BIT + 1);
564   inex = mpfr_ui_sub (x, 1, eps, MPFR_RNDN);
565   MPFR_ASSERTN (inex == 0);  /* since n < 2^(size_of_long_in_bits) */
566   inex = mpfr_div_2ui (x, x, 1, MPFR_RNDN);  /* 1/2 - eps/2 exactly */
567   MPFR_ASSERTN (inex == 0);
568 
569   mpfr_init2 (y, sizeof (unsigned long) * CHAR_BIT);
570   inex = mpfr_set_ui (y, n, MPFR_RNDN);
571   MPFR_ASSERTN (inex == 0);
572 
573   /* 0 < eps < 1 / (2n), thus (1 - eps)^n > 1/2,
574      and 1/2 (1/2)^n < (1/2 - eps/2)^n < (1/2)^n. */
575   mpfr_inits2 (64, z, z0, (mpfr_ptr) 0);
576   RND_LOOP_NO_RNDF (rnd)
577     {
578       unsigned int ufinex = MPFR_FLAGS_UNDERFLOW | MPFR_FLAGS_INEXACT;
579       int expected_inex;
580       char sy[256];
581 
582       mpfr_set_ui (z0, 0, MPFR_RNDN);
583       expected_inex = rnd == MPFR_RNDN || rnd == MPFR_RNDU || rnd == MPFR_RNDA ?
584         (mpfr_nextabove (z0), 1) : -1;
585       sprintf (sy, "%lu", (unsigned long) n);
586 
587       mpfr_clear_flags ();
588       inex = mpfr_pow (z, x, y, (mpfr_rnd_t) rnd);
589       cmpres (0, x, sy, (mpfr_rnd_t) rnd, z0, expected_inex, z, inex, ufinex,
590               "underflow_up2", "mpfr_pow");
591       test_others (NULL, sy, (mpfr_rnd_t) rnd, x, y, z, inex, ufinex,
592                    "underflow_up2");
593     }
594 
595   mpfr_clears (x, y, z, z0, eps, (mpfr_ptr) 0);
596 }
597 
598 static void
underflow_up3(void)599 underflow_up3 (void)
600 {
601   mpfr_t x, y, z, z0;
602   int inex;
603   int rnd;
604   int i;
605 
606   mpfr_init2 (x, 64);
607   mpfr_init2 (y, sizeof (mpfr_exp_t) * CHAR_BIT);
608   mpfr_init2 (z, 32);
609   mpfr_init2 (z0, 2);
610 
611   inex = mpfr_set_exp_t (y, mpfr_get_emin () - 2, MPFR_RNDN);
612   MPFR_ASSERTN (inex == 0);
613   for (i = -1; i <= 1; i++)
614     RND_LOOP_NO_RNDF (rnd)
615       {
616         unsigned int ufinex = MPFR_FLAGS_UNDERFLOW | MPFR_FLAGS_INEXACT;
617         int expected_inex;
618 
619         mpfr_set_ui (x, 2, MPFR_RNDN);
620         if (i < 0)
621           mpfr_nextbelow (x);
622         if (i > 0)
623           mpfr_nextabove (x);
624         /* x = 2 + i * eps, y = emin - 2, x^y ~= 2^(emin - 2) */
625 
626         expected_inex = rnd == MPFR_RNDU || rnd == MPFR_RNDA
627           || (rnd == MPFR_RNDN && i < 0) ? 1 : -1;
628 
629         mpfr_set_ui (z0, 0, MPFR_RNDN);
630         if (expected_inex > 0)
631           mpfr_nextabove (z0);
632 
633         mpfr_clear_flags ();
634         inex = mpfr_pow (z, x, y, (mpfr_rnd_t) rnd);
635         cmpres (0, x, "emin - 2", (mpfr_rnd_t) rnd, z0, expected_inex, z, inex,
636                 ufinex, "underflow_up3", "mpfr_pow");
637         test_others (NULL, "emin - 2", (mpfr_rnd_t) rnd, x, y, z, inex, ufinex,
638                      "underflow_up3");
639       }
640 
641   mpfr_clears (x, y, z, z0, (mpfr_ptr) 0);
642 }
643 
644 static void
underflow_up(void)645 underflow_up (void)
646 {
647   underflow_up1 ();
648   underflow_up2 ();
649   underflow_up3 ();
650 }
651 
652 static void
overflow_inv(void)653 overflow_inv (void)
654 {
655   mpfr_t x, y, z;
656   int precx;
657   int s, t;
658   int inex;
659   int rnd;
660 
661   mpfr_init2 (y, 2);
662   mpfr_init2 (z, 8);
663 
664   mpfr_set_si (y, -1, MPFR_RNDN);
665   for (precx = 10; precx <= 100; precx += 90)
666     {
667       const char *sp = precx == 10 ?
668         "overflow_inv (precx = 10)" : "overflow_inv (precx = 100)";
669 
670       mpfr_init2 (x, precx);
671       for (s = -1; s <= 1; s += 2)
672         {
673           inex = mpfr_set_si_2exp (x, s, - mpfr_get_emax (), MPFR_RNDN);
674           MPFR_ASSERTN (inex == 0);
675           for (t = 0; t <= 5; t++)
676             {
677               /* If precx = 10:
678                * x = s * 2^(-emax) * (1 + t * 2^(-9)), so that
679                * 1/x = s * 2^emax * (1 - t * 2^(-9) + eps) with eps > 0.
680                * Values of (1/x) / 2^emax and overflow condition for x > 0:
681                * t = 0: 1                           o: always
682                * t = 1: 0.11111111 100000000011...  o: MPFR_RNDN and MPFR_RNDU
683                * t = 2: 0.11111111 000000001111...  o: MPFR_RNDU
684                * t = 3: 0.11111110 100000100011...  o: never
685                *
686                * If precx = 100:
687                * t = 0: always overflow
688                * t > 0: overflow for MPFR_RNDN and MPFR_RNDU.
689                */
690               RND_LOOP_NO_RNDF (rnd)
691                 {
692                   int inf, overflow;
693                   mpfr_rnd_t rnd2;
694 
695                   if (rnd == MPFR_RNDA)
696                     rnd2 = s < 0 ? MPFR_RNDD : MPFR_RNDU;
697                   else
698                     rnd2 = (mpfr_rnd_t) rnd;
699 
700                   overflow = t == 0 ||
701                     ((mpfr_rnd_t) rnd == MPFR_RNDN &&
702                      (precx > 10 || t == 1)) ||
703                     (rnd2 == (s < 0 ? MPFR_RNDD : MPFR_RNDU) &&
704                      (precx > 10 || t <= 2));
705                   inf = overflow &&
706                     ((mpfr_rnd_t) rnd == MPFR_RNDN ||
707                      rnd2 == (s < 0 ? MPFR_RNDD : MPFR_RNDU));
708                   mpfr_clear_flags ();
709                   inex = mpfr_pow (z, x, y, (mpfr_rnd_t) rnd);
710                   if (overflow ^ !! mpfr_overflow_p ())
711                     {
712                       printf ("Bad overflow flag in %s\nfor mpfr_pow%s\n"
713                               "s = %d, t = %d, %s\n", sp,
714                               ext ? ", extended exponent range" : "",
715                               s, t, mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
716                       exit (1);
717                     }
718                   if (overflow && (inf ^ !! MPFR_IS_INF (z)))
719                     {
720                       printf ("Bad value in %s\nfor mpfr_pow%s\n"
721                               "s = %d, t = %d, %s\nGot ", sp,
722                               ext ? ", extended exponent range" : "",
723                               s, t, mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
724                       mpfr_out_str (stdout, 16, 0, z, MPFR_RNDN);
725                       printf (" instead of %s value.\n",
726                               inf ? "infinite" : "finite");
727                       exit (1);
728                     }
729                   test_others (NULL, "-1", (mpfr_rnd_t) rnd, x, y, z,
730                                inex, __gmpfr_flags, sp);
731                 }  /* RND_LOOP */
732               mpfr_nexttoinf (x);
733             }  /* for (t = ...) */
734         }  /* for (s = ...) */
735       mpfr_clear (x);
736     }  /* for (precx = ...) */
737 
738   mpfr_clears (y, z, (mpfr_ptr) 0);
739 }
740 
741 static void
alltst(void)742 alltst (void)
743 {
744   mpfr_exp_t emin, emax;
745 
746   ext = 0;
747   tst ();
748   underflow_up ();
749   overflow_inv ();
750 
751   emin = mpfr_get_emin ();
752   emax = mpfr_get_emax ();
753   set_emin (MPFR_EMIN_MIN);
754   set_emax (MPFR_EMAX_MAX);
755   if (mpfr_get_emin () != emin || mpfr_get_emax () != emax)
756     {
757       ext = 1;
758       tst ();
759       underflow_up ();
760       overflow_inv ();
761       set_emin (emin);
762       set_emax (emax);
763     }
764 }
765 
766 int
main(int argc,char * argv[])767 main (int argc, char *argv[])
768 {
769   tests_start_mpfr ();
770   all_cmpres_errors = argc > 1;
771   alltst ();
772   tests_end_mpfr ();
773   return all_cmpres_errors < 0;
774 }
775