xref: /netbsd-src/external/lgpl3/mpfr/dist/tests/tgeneric.c (revision c7c727fae85036860d5bb848f2730ff419e2b060)
1 /* Generic test file for functions with one or two arguments (the second being
2    either mpfr_t or double).
3 
4 Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
5 Contributed by the Arenaire and Cacao projects, INRIA.
6 
7 This file is part of the GNU MPFR Library.
8 
9 The GNU MPFR Library is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
13 
14 The GNU MPFR Library is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17 License for more details.
18 
19 You should have received a copy of the GNU Lesser General Public License
20 along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
21 http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
22 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
23 
24 /* define TWO_ARGS for two-argument functions like mpfr_pow
25    define DOUBLE_ARG1 or DOUBLE_ARG2 for function with a double operand in
26    first or second place like sub_d or d_sub */
27 
28 #ifndef TEST_RANDOM_POS
29 /* For the random function: one number on two is negative. */
30 #define TEST_RANDOM_POS 256
31 #endif
32 
33 #ifndef TEST_RANDOM_POS2
34 /* For the random function: one number on two is negative. */
35 #define TEST_RANDOM_POS2 256
36 #endif
37 
38 #ifndef TEST_RANDOM_EMIN
39 #define TEST_RANDOM_EMIN -256
40 #endif
41 
42 #ifndef TEST_RANDOM_EMAX
43 #define TEST_RANDOM_EMAX 255
44 #endif
45 
46 /* The (void *) below is needed to avoid a warning with gcc 4.2+ and functions
47  * with 2 arguments. See <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36299>.
48  */
49 #define TGENERIC_FAIL(S, X, U)                                          \
50   do                                                                    \
51     {                                                                   \
52       printf ("%s\nx = ", (S));                                         \
53       mpfr_out_str (stdout, 2, 0, (X), MPFR_RNDN);                       \
54       printf ("\n");                                                    \
55       if ((void *) U != 0)                                              \
56         {                                                               \
57           printf ("u = ");                                              \
58           mpfr_out_str (stdout, 2, 0, (U), MPFR_RNDN);                   \
59           printf ("\n");                                                \
60         }                                                               \
61       printf ("yprec = %u, rnd_mode = %s, inexact = %d, flags = %u\n",  \
62               (unsigned int) yprec, mpfr_print_rnd_mode (rnd), compare, \
63               (unsigned int) __gmpfr_flags);                            \
64       exit (1);                                                         \
65     }                                                                   \
66   while (0)
67 
68 #undef TGENERIC_CHECK
69 #if defined(TWO_ARGS) || defined(DOUBLE_ARG1) || defined(DOUBLE_ARG2)
70 #define TGENERIC_CHECK(S, EXPR) \
71   do if (!(EXPR)) TGENERIC_FAIL (S, x, u); while (0)
72 #else
73 #define TGENERIC_CHECK(S, EXPR) \
74   do if (!(EXPR)) TGENERIC_FAIL (S, x, 0); while (0)
75 #endif
76 
77 #ifdef DEBUG_TGENERIC
78 #define STR(F) #F
79 #define TGENERIC_IAUX(F,P,X,U)                                          \
80   do                                                                    \
81     {                                                                   \
82       printf ("tgeneric: testing function " STR(F)                      \
83               ", %s, target prec = %lu\nx = ",                          \
84               mpfr_print_rnd_mode (rnd), (unsigned long) (P));          \
85       mpfr_out_str (stdout, 2, 0, (X), MPFR_RNDN);                       \
86       printf ("\n");                                                    \
87       if (U)                                                            \
88         {                                                               \
89           printf ("u = ");                                              \
90           mpfr_out_str (stdout, 2, 0, (U), MPFR_RNDN);                   \
91           printf ("\n");                                                \
92         }                                                               \
93     }                                                                   \
94   while (0)
95 #undef TGENERIC_INFO
96 #if defined(TWO_ARGS) || defined(DOUBLE_ARG1) || defined(DOUBLE_ARG2)
97 #define TGENERIC_INFO(F,P) TGENERIC_IAUX(F,P,x,u)
98 #else
99 #define TGENERIC_INFO(F,P) TGENERIC_IAUX(F,P,x,0)
100 #endif
101 #endif
102 
103 /* For some functions (for example cos), the argument reduction is too
104    expensive when using mpfr_get_emax(). Then simply define REDUCE_EMAX
105    to some reasonable value before including tgeneric.c. */
106 #ifndef REDUCE_EMAX
107 #define REDUCE_EMAX mpfr_get_emax ()
108 #endif
109 
110 static void
111 test_generic (mpfr_prec_t p0, mpfr_prec_t p1, unsigned int N)
112 {
113   mpfr_prec_t prec, xprec, yprec;
114   mpfr_t x, y, z, t, w;
115 #ifdef TWO_ARGS
116   mpfr_t u;
117 #elif defined(DOUBLE_ARG1) || defined(DOUBLE_ARG2)
118   mpfr_t u;
119   double d;
120 #endif
121   mpfr_rnd_t rnd;
122   int inexact, compare, compare2;
123   unsigned int n;
124   unsigned long ctrt = 0, ctrn = 0;
125   mpfr_exp_t old_emin, old_emax;
126 
127   old_emin = mpfr_get_emin ();
128   old_emax = mpfr_get_emax ();
129 
130   mpfr_inits2 (MPFR_PREC_MIN, x, y, z, t, w, (mpfr_ptr) 0);
131 #if defined(TWO_ARGS) || defined(DOUBLE_ARG1) || defined(DOUBLE_ARG2)
132   mpfr_init2 (u, MPFR_PREC_MIN);
133 #endif
134 
135   /* generic test */
136   for (prec = p0; prec <= p1; prec++)
137     {
138       mpfr_set_prec (z, prec);
139       mpfr_set_prec (t, prec);
140       yprec = prec + 10;
141       mpfr_set_prec (y, yprec);
142       mpfr_set_prec (w, yprec);
143 
144       /* Note: in precision p1, we test 4 special cases. */
145       for (n = 0; n < (prec == p1 ? N + 4 : N); n++)
146         {
147           xprec = prec;
148           if (randlimb () & 1)
149             {
150               xprec *= (double) randlimb () / MP_LIMB_T_MAX;
151               if (xprec < MPFR_PREC_MIN)
152                 xprec = MPFR_PREC_MIN;
153             }
154           mpfr_set_prec (x, xprec);
155 #ifdef TWO_ARGS
156           mpfr_set_prec (u, xprec);
157 #elif defined(DOUBLE_ARG1) || defined(DOUBLE_ARG2)
158           mpfr_set_prec (u, IEEE_DBL_MANT_DIG);
159 #endif
160 
161           if (n > 3 || prec < p1)
162             {
163 #if defined(RAND_FUNCTION)
164               RAND_FUNCTION (x);
165 #if defined(TWO_ARGS) || defined(DOUBLE_ARG1) || defined(DOUBLE_ARG2)
166               RAND_FUNCTION (u);
167 #endif
168 #else
169               tests_default_random (x, TEST_RANDOM_POS,
170                                     TEST_RANDOM_EMIN, TEST_RANDOM_EMAX);
171 #if defined(TWO_ARGS) || defined(DOUBLE_ARG1) || defined(DOUBLE_ARG2)
172               tests_default_random (u, TEST_RANDOM_POS2,
173                                     TEST_RANDOM_EMIN, TEST_RANDOM_EMAX);
174 #endif
175 #endif
176             }
177           else
178             {
179               /* Special cases tested in precision p1 if n <= 3. They are
180                  useful really in the extended exponent range. */
181               set_emin (MPFR_EMIN_MIN);
182               set_emax (MPFR_EMAX_MAX);
183               if (n <= 1)
184                 {
185                   mpfr_set_si (x, n == 0 ? 1 : -1, MPFR_RNDN);
186                   mpfr_set_exp (x, mpfr_get_emin ());
187 #if defined(TWO_ARGS) || defined(DOUBLE_ARG1) || defined(DOUBLE_ARG2)
188                   mpfr_set_si (u, randlimb () % 2 == 0 ? 1 : -1, MPFR_RNDN);
189                   mpfr_set_exp (u, mpfr_get_emin ());
190 #endif
191                 }
192               else  /* 2 <= n <= 3 */
193                 {
194                   if (getenv ("MPFR_CHECK_MAX") == NULL)
195                     goto next_n;
196                   mpfr_set_si (x, n == 0 ? 1 : -1, MPFR_RNDN);
197                   mpfr_setmax (x, REDUCE_EMAX);
198 #if defined(TWO_ARGS) || defined(DOUBLE_ARG1) || defined(DOUBLE_ARG2)
199                   mpfr_set_si (u, randlimb () % 2 == 0 ? 1 : -1, MPFR_RNDN);
200                   mpfr_setmax (u, mpfr_get_emax ());
201 #endif
202                 }
203             }
204 
205           rnd = RND_RAND ();
206           mpfr_clear_flags ();
207 #ifdef DEBUG_TGENERIC
208           TGENERIC_INFO (TEST_FUNCTION, MPFR_PREC (y));
209 #endif
210 #if defined(TWO_ARGS)
211           compare = TEST_FUNCTION (y, x, u, rnd);
212 #elif defined(DOUBLE_ARG1)
213           d = mpfr_get_d (u, rnd);
214           compare = TEST_FUNCTION (y, d, x, rnd);
215 #elif defined(DOUBLE_ARG2)
216           d = mpfr_get_d (u, rnd);
217           compare = TEST_FUNCTION (y, x, d, rnd);
218 #else
219           compare = TEST_FUNCTION (y, x, rnd);
220 #endif
221           TGENERIC_CHECK ("Bad inexact flag",
222                           (compare != 0) ^ (mpfr_inexflag_p () == 0));
223           ctrt++;
224           /* Consistency test in a reduced exponent range. Doing it
225              for the first 10 samples and for prec == p1 (which has
226              some special cases) should be sufficient. */
227           if (ctrt <= 10 || prec == p1)
228             {
229               unsigned int flags, oldflags = __gmpfr_flags;
230               mpfr_exp_t e, emin, emax, oemin, oemax;
231 
232               /* Determine the smallest exponent range containing the
233                  exponents of the mpfr_t inputs (x, and u if TWO_ARGS)
234                  and output (y). */
235               emin = MPFR_EMAX_MAX;
236               emax = MPFR_EMIN_MIN;
237               if (MPFR_IS_PURE_FP (x))
238                 {
239                   e = MPFR_GET_EXP (x);
240                   if (e < emin)
241                     emin = e;
242                   if (e > emax)
243                     emax = e;
244                 }
245               if (MPFR_IS_PURE_FP (y))
246                 {
247                   e = MPFR_GET_EXP (y);
248                   if (e < emin)
249                     emin = e;
250                   if (e > emax)
251                     emax = e;
252                 }
253 #if defined(TWO_ARGS)
254               if (MPFR_IS_PURE_FP (u))
255                 {
256                   e = MPFR_GET_EXP (u);
257                   if (e < emin)
258                     emin = e;
259                   if (e > emax)
260                     emax = e;
261                 }
262 #endif
263               if (emin > emax)
264                 emin = emax;  /* case where all values are singular */
265               oemin = mpfr_get_emin ();
266               oemax = mpfr_get_emax ();
267               mpfr_set_emin (emin);
268               mpfr_set_emax (emax);
269               mpfr_clear_flags ();
270 #if defined(TWO_ARGS)
271               inexact = TEST_FUNCTION (w, x, u, rnd);
272 #elif defined(DOUBLE_ARG1)
273               inexact = TEST_FUNCTION (w, d, x, rnd);
274 #elif defined(DOUBLE_ARG2)
275               inexact = TEST_FUNCTION (w, x, d, rnd);
276 #else
277               inexact = TEST_FUNCTION (w, x, rnd);
278 #endif
279               flags = __gmpfr_flags;
280               mpfr_set_emin (oemin);
281               mpfr_set_emax (oemax);
282               if (! (SAME_VAL (w, y) &&
283                      SAME_SIGN (inexact, compare) &&
284                      flags == oldflags))
285                 {
286                   printf ("Error in reduced exponent range [%"
287                           MPFR_EXP_FSPEC "d,%" MPFR_EXP_FSPEC "d] on:\n",
288                           (mpfr_eexp_t) emin, (mpfr_eexp_t) emax);
289                   printf ("x = ");
290                   mpfr_dump (x);
291 #if defined(TWO_ARGS) || defined(DOUBLE_ARG1) || defined(DOUBLE_ARG2)
292                   printf ("u = ");
293                   mpfr_dump (u);
294 #endif
295                   printf ("yprec = %u, rnd_mode = %s\n",
296                           (unsigned int) yprec, mpfr_print_rnd_mode (rnd));
297                   printf ("Expected:\n  y = ");
298                   mpfr_dump (y);
299                   printf ("  inex = %d, flags = %u\n",
300                           SIGN (compare), oldflags);
301                   printf ("Got:\n  w = ");
302                   mpfr_dump (w);
303                   printf ("  inex = %d, flags = %u\n",
304                           SIGN (inexact), flags);
305                   exit (1);
306                 }
307             }
308           if (MPFR_IS_SINGULAR (y))
309             {
310               if (MPFR_IS_NAN (y) || mpfr_nanflag_p ())
311                 TGENERIC_CHECK ("Bad NaN flag",
312                                 MPFR_IS_NAN (y) && mpfr_nanflag_p ());
313               else if (MPFR_IS_INF (y))
314                 TGENERIC_CHECK ("Bad overflow flag",
315                                 (compare != 0) ^ (mpfr_overflow_p () == 0));
316               else if (MPFR_IS_ZERO (y))
317                 TGENERIC_CHECK ("Bad underflow flag",
318                                 (compare != 0) ^ (mpfr_underflow_p () == 0));
319             }
320           else if (mpfr_overflow_p ())
321             {
322               TGENERIC_CHECK ("Bad compare value (overflow)", compare != 0);
323               mpfr_nexttoinf (y);
324               TGENERIC_CHECK ("Should have been max MPFR number",
325                               MPFR_IS_INF (y));
326             }
327           else if (mpfr_underflow_p ())
328             {
329               TGENERIC_CHECK ("Bad compare value (underflow)", compare != 0);
330               mpfr_nexttozero (y);
331               TGENERIC_CHECK ("Should have been min MPFR number",
332                               MPFR_IS_ZERO (y));
333             }
334           else if (mpfr_can_round (y, yprec, rnd, rnd, prec))
335             {
336               ctrn++;
337               mpfr_set (t, y, rnd);
338               /* Risk of failures are known when some flags are already set
339                  before the function call. Do not set the erange flag, as
340                  it will remain set after the function call and no checks
341                  are performed in such a case (see the mpfr_erangeflag_p
342                  test below). */
343               if (randlimb () & 1)
344                 __gmpfr_flags = MPFR_FLAGS_ALL ^ MPFR_FLAGS_ERANGE;
345 #ifdef DEBUG_TGENERIC
346               TGENERIC_INFO (TEST_FUNCTION, MPFR_PREC (z));
347 #endif
348               /* Let's increase the precision of the inputs in a random way.
349                  In most cases, this doesn't make any difference, but for
350                  the mpfr_fmod bug fixed in r6230, this triggers the bug. */
351               mpfr_prec_round (x, mpfr_get_prec (x) + (randlimb () & 15),
352                                MPFR_RNDN);
353 #if defined(TWO_ARGS)
354               mpfr_prec_round (u, mpfr_get_prec (u) + (randlimb () & 15),
355                                MPFR_RNDN);
356               inexact = TEST_FUNCTION (z, x, u, rnd);
357 #elif defined(DOUBLE_ARG1)
358               inexact = TEST_FUNCTION (z, d, x, rnd);
359 #elif defined(DOUBLE_ARG2)
360               inexact = TEST_FUNCTION (z, x, d, rnd);
361 #else
362               inexact = TEST_FUNCTION (z, x, rnd);
363 #endif
364               if (mpfr_erangeflag_p ())
365                 goto next_n;
366               if (mpfr_nan_p (z) || mpfr_cmp (t, z) != 0)
367                 {
368                   printf ("results differ for x=");
369                   mpfr_out_str (stdout, 2, xprec, x, MPFR_RNDN);
370 #ifdef TWO_ARGS
371                   printf ("\nu=");
372                   mpfr_out_str (stdout, 2, xprec, u, MPFR_RNDN);
373 #elif defined(DOUBLE_ARG1) || defined(DOUBLE_ARG2)
374                   printf ("\nu=");
375                   mpfr_out_str (stdout, 2, IEEE_DBL_MANT_DIG, u, MPFR_RNDN);
376 #endif
377                   printf (" prec=%u rnd_mode=%s\n", (unsigned) prec,
378                           mpfr_print_rnd_mode (rnd));
379                   printf ("got      ");
380                   mpfr_out_str (stdout, 2, prec, z, MPFR_RNDN);
381                   puts ("");
382                   printf ("expected ");
383                   mpfr_out_str (stdout, 2, prec, t, MPFR_RNDN);
384                   puts ("");
385                   printf ("approx   ");
386                   mpfr_print_binary (y);
387                   puts ("");
388                   exit (1);
389                 }
390               compare2 = mpfr_cmp (t, y);
391               /* if rounding to nearest, cannot know the sign of t - f(x)
392                  because of composed rounding: y = o(f(x)) and t = o(y) */
393               if (compare * compare2 >= 0)
394                 compare = compare + compare2;
395               else
396                 compare = inexact; /* cannot determine sign(t-f(x)) */
397               if (((inexact == 0) && (compare != 0)) ||
398                   ((inexact > 0) && (compare <= 0)) ||
399                   ((inexact < 0) && (compare >= 0)))
400                 {
401                   printf ("Wrong inexact flag for rnd=%s: expected %d, got %d"
402                           "\n", mpfr_print_rnd_mode (rnd), compare, inexact);
403                   printf ("x="); mpfr_print_binary (x); puts ("");
404 #if defined(TWO_ARGS) || defined(DOUBLE_ARG1) || defined(DOUBLE_ARG2)
405                   printf ("u="); mpfr_print_binary (u); puts ("");
406 #endif
407                   printf ("y="); mpfr_print_binary (y); puts ("");
408                   printf ("t="); mpfr_print_binary (t); puts ("");
409                   exit (1);
410                 }
411             }
412           else if (getenv ("MPFR_SUSPICIOUS_OVERFLOW") != NULL)
413             {
414               /* For developers only! */
415               MPFR_ASSERTN (MPFR_IS_PURE_FP (y));
416               mpfr_nexttoinf (y);
417               if (MPFR_IS_INF (y) && MPFR_IS_LIKE_RNDZ (rnd, MPFR_IS_NEG (y))
418                   && !mpfr_overflow_p ())
419                 {
420                   printf ("Possible bug! |y| is the maximum finite number "
421                           "and has been obtained when\nrounding toward zero"
422                           " (%s). Thus there is a very probable overflow,\n"
423                           "but the overflow flag is not set!\n",
424                           mpfr_print_rnd_mode (rnd));
425                   printf ("x="); mpfr_print_binary (x); puts ("");
426 #if defined(TWO_ARGS) || defined(DOUBLE_ARG1) || defined(DOUBLE_ARG2)
427                   printf ("u="); mpfr_print_binary (u); puts ("");
428 #endif
429                   exit (1);
430                 }
431             }
432 
433         next_n:
434           /* In case the exponent range has been changed by
435              tests_default_random() or for special values... */
436           mpfr_set_emin (old_emin);
437           mpfr_set_emax (old_emax);
438         }
439     }
440 
441 #ifndef TGENERIC_NOWARNING
442   if (3 * ctrn < 2 * ctrt)
443     printf ("Warning! Too few normal cases in generic tests (%lu / %lu)\n",
444             ctrn, ctrt);
445 #endif
446 
447   mpfr_clears (x, y, z, t, w, (mpfr_ptr) 0);
448 #if defined(TWO_ARGS) || defined(DOUBLE_ARG1) || defined(DOUBLE_ARG2)
449   mpfr_clear (u);
450 #endif
451 }
452 
453 #undef TEST_RANDOM_POS
454 #undef TEST_RANDOM_POS2
455 #undef TEST_RANDOM_EMIN
456 #undef TEST_RANDOM_EMAX
457 #undef RAND_FUNCTION
458 #undef TWO_ARGS
459 #undef TWO_ARGS_UI
460 #undef TEST_FUNCTION
461 #undef test_generic
462