xref: /netbsd/external/lgpl3/mpfr/dist/tests/tests.c (revision 606004a0)
1 /* Miscellaneous support for test programs.
2 
3 Copyright 2001-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 on macro definitions are already done in src/init2.c
24  * as static assertions (in general). This allows one to get a failure at
25  * build time in case of inconsistency (probably due to search path issues
26  * in header file inclusion). This does not need to be done again in the
27  * test suite.
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33 
34 #include <float.h>
35 
36 #ifdef HAVE_LOCALE_H
37 #include <locale.h>
38 #endif
39 
40 #ifdef MPFR_TESTS_FPE_DIV
41 # ifdef MPFR_TESTS_FPE_TRAP
42 #  define _GNU_SOURCE /* for feenableexcept */
43 # endif
44 # include <fenv.h>
45 #endif
46 
47 #ifdef HAVE_GETTIMEOFDAY
48 # include <sys/time.h>
49 #else
50 # include <time.h>
51 #endif
52 
53 /* <sys/fpu.h> is needed to have union fpc_csr defined under IRIX64
54    (see below). Let's include it only if need be. */
55 #if defined HAVE_SYS_FPU_H && defined HAVE_FPC_CSR
56 # include <sys/fpu.h>
57 #endif
58 
59 #ifdef MPFR_TESTS_TIMEOUT
60 #include <sys/resource.h>
61 #endif
62 
63 #if defined(HAVE_SIGNAL) || defined(HAVE_SIGACTION)
64 # include <signal.h>
65 #endif
66 
67 #include "mpfr-test.h"
68 
69 #ifdef MPFR_FPU_PREC
70 /* This option allows to test MPFR on x86 processors when the FPU
71  * rounding precision has been changed. As MPFR is a library, this can
72  * occur in practice, either by the calling software or by some other
73  * library or plug-in used by the calling software. This option is
74  * mainly for developers. If it is used, then the <fpu_control.h>
75  * header is assumed to exist and work like under Linux/x86. MPFR does
76  * not need to be recompiled. So, a possible usage is the following:
77  *
78  *   cd tests
79  *   make clean
80  *   make check CFLAGS="-g -O2 -ffloat-store -DMPFR_FPU_PREC=_FPU_SINGLE"
81  *
82  * i.e. just add -DMPFR_FPU_PREC=... to the CFLAGS found in Makefile.
83  *
84  * Notes:
85  *   + SSE2 (used to implement double's on x86_64, and possibly on x86
86  *     too, depending on the compiler configuration and flags) is not
87  *     affected by the dynamic precision.
88  *   + When the FPU is set to single precision, the behavior of MPFR
89  *     functions that have a native floating-point type (float, double,
90  *     long double) as argument or return value is not guaranteed.
91  */
92 
93 #include <fpu_control.h>
94 
95 static void
set_fpu_prec(void)96 set_fpu_prec (void)
97 {
98   fpu_control_t cw;
99 
100   _FPU_GETCW(cw);
101   cw &= ~(_FPU_EXTENDED|_FPU_DOUBLE|_FPU_SINGLE);
102   cw |= (MPFR_FPU_PREC);
103   _FPU_SETCW(cw);
104 }
105 
106 #endif
107 
108 char             mpfr_rands_initialized = 0;
109 gmp_randstate_t  mpfr_rands;
110 
111 char *locale = NULL;
112 
113 /* Programs that test GMP's mp_set_memory_functions() need to set
114    tests_memory_disabled = 2 before calling tests_start_mpfr(). */
115 #ifdef MPFR_USE_MINI_GMP
116 /* disable since mini-gmp does not keep track of old_size in realloc/free */
117 int tests_memory_disabled = 1;
118 #else
119 int tests_memory_disabled = 0;
120 #endif
121 
122 static mpfr_exp_t default_emin, default_emax;
123 
124 static void tests_rand_start (void);
125 static void tests_rand_end   (void);
126 static void tests_limit_start (void);
127 
128 /* We want to always import the function mpfr_dump inside the test
129    suite, so that we can use it in GDB. But it doesn't work if we build
130    a Windows DLL (initializer element is not a constant) */
131 #if !__GMP_LIBGMP_DLL
132 extern void (*dummy_func) (mpfr_srcptr);
133 void (*dummy_func)(mpfr_srcptr) = mpfr_dump;
134 #endif
135 
136 /* Various version checks.
137    A mismatch on the GMP version is not regarded as fatal. A mismatch
138    on the MPFR version is regarded as fatal, since this means that we
139    would not check the MPFR library that has just been built (the goal
140    of "make check") but a different library that is already installed,
141    i.e. any test result would be meaningless; in such a case, we exit
142    immediately with an error (exit status = 1).
143    Return value: 0 for no errors, 1 in case of any non-fatal error.
144    Note: If the return value is 0, no data must be sent to stdout. */
145 int
test_version(void)146 test_version (void)
147 {
148   const char *version;
149   char buffer[256];
150   int err = 0;
151 
152 #ifndef MPFR_USE_MINI_GMP
153   sprintf (buffer, "%d.%d.%d", __GNU_MP_VERSION, __GNU_MP_VERSION_MINOR,
154            __GNU_MP_VERSION_PATCHLEVEL);
155   if (strcmp (buffer, gmp_version) != 0 &&
156       (__GNU_MP_VERSION_PATCHLEVEL != 0 ||
157        (sprintf (buffer, "%d.%d", __GNU_MP_VERSION, __GNU_MP_VERSION_MINOR),
158         strcmp (buffer, gmp_version) != 0)))
159     err = 1;
160 
161   /* In some cases, it may be acceptable to have different versions for
162      the header and the library, in particular when shared libraries are
163      used (e.g., after a bug-fix upgrade of the library, and versioning
164      ensures that this can be done only when the binary interface is
165      compatible). However, when recompiling software like here, this
166      should never happen (except if GMP has been upgraded between two
167      "make check" runs, but there's no reason for that). A difference
168      between the versions of gmp.h and libgmp probably indicates either
169      a bad configuration or some other inconsistency in the development
170      environment, and it is better to fail (in particular for automatic
171      installations). */
172   if (err)
173     {
174       printf ("ERROR! The versions of gmp.h (%s) and libgmp (%s) do not "
175               "match.\nThe possible causes are:\n", buffer, gmp_version);
176       printf ("  * A bad configuration in your include/library search paths.\n"
177               "  * An inconsistency in the include/library search paths of\n"
178               "    your development environment; an example:\n"
179               "      "
180               "https://gcc.gnu.org/legacy-ml/gcc-help/2010-11/msg00359.html\n"
181               "  * GMP has been upgraded after the first \"make check\".\n"
182               "    In such a case, try again after a \"make clean\".\n"
183               "  * A new or non-standard version naming is used in GMP.\n"
184               "    In this case, a patch may already be available on the\n"
185               "    MPFR web site.  Otherwise please report the problem.\n");
186       printf ("In the first two cases, this may lead to errors, in particular"
187               " with MPFR.\nIf some other tests fail, please solve that"
188               " problem first.\n");
189     }
190 #endif
191 
192   /* VL: I get the following error on an OpenSUSE machine, and changing
193      the value of shlibpath_overrides_runpath in the libtool file from
194      'no' to 'yes' fixes the problem. */
195   version = mpfr_get_version ();
196   if (strcmp (MPFR_VERSION_STRING, version) == 0)
197     {
198       int i;
199 
200       sprintf (buffer, "%d.%d.%d", MPFR_VERSION_MAJOR, MPFR_VERSION_MINOR,
201                MPFR_VERSION_PATCHLEVEL);
202       for (i = 0; buffer[i] == version[i]; i++)
203         if (buffer[i] == '\0')
204           return err;
205       if (buffer[i] == '\0' && version[i] == '-')
206         return err;
207       printf ("%sMPFR_VERSION_MAJOR.MPFR_VERSION_MINOR.MPFR_VERSION_PATCHLEVEL"
208               " (%s)\nand MPFR_VERSION_STRING (%s) do not match!\nIt seems "
209               "that the mpfr.h file has been corrupted.\n", err ? "\n" : "",
210               buffer, version);
211     }
212   else
213     printf (
214       "%sIncorrect MPFR version! (%s header vs %s library)\n"
215       "Nothing else has been tested since for this reason, any other test\n"
216       "may fail.  Please fix this problem first, as suggested below.  It\n"
217       "probably comes from libtool (included in the MPFR tarball), which\n"
218       "is responsible for setting up the search paths depending on the\n"
219       "platform, or automake.\n"
220       "  * On some platforms such as Solaris, $LD_LIBRARY_PATH overrides\n"
221       "    the rpath, and if the MPFR library is already installed in a\n"
222       "    $LD_LIBRARY_PATH directory, you typically get this error.  Do\n"
223       "    not use $LD_LIBRARY_PATH permanently on such platforms; it may\n"
224       "    also break other things.\n"
225       "  * You may have an ld option that specifies a library search path\n"
226       "    where MPFR can be found, taking the precedence over the path\n"
227       "    added by libtool.  Check your environment variables, such as\n"
228       "    LD_OPTIONS under Solaris.  Moreover, under Solaris, the run path\n"
229       "    generated by libtool 2.4.6 may be incorrect: the build directory\n"
230       "    may not appear first in the run path; set $LD_LIBRARY_PATH to\n"
231       "    /path/to/builddir/src/.libs for the tests as a workaround.\n"
232       "  * Then look at https://www.mpfr.org/mpfr-current/ for any update.\n"
233       "  * Try again on a completely clean source (some errors might come\n"
234       "    from a previous build or previous source changes).\n"
235       "  * If the error still occurs, you can try to change the value of\n"
236       "    shlibpath_overrides_runpath ('yes' or 'no') in the \"libtool\"\n"
237       "    file and rebuild MPFR (make clean && make && make check).  You\n"
238       "    may want to report the problem to the libtool and/or automake\n"
239       "    developers, with the effect of this change.\n",
240       err ? "\n" : "", MPFR_VERSION_STRING, version);
241   /* Note about $LD_LIBRARY_PATH under Solaris:
242    *   https://en.wikipedia.org/wiki/Rpath#Solaris_ld.so
243    * This cause has been confirmed by a user who got this error.
244    * And about the libtool 2.4.6 bug also concerning Solaris:
245    *   https://debbugs.gnu.org/cgi/bugreport.cgi?bug=30222
246    *   https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=888059
247    */
248   exit (1);
249 }
250 
251 /* The inexact exception occurs very often, and is normal.
252    The underflow exception also might occur, for example in test_generic
253    for mpfr_xxx_d functions. Same for overflow. Thus we only check for
254    the division-by-zero and invalid exceptions, which should not occur
255    inside MPFR. */
256 #define FPE_FLAGS (FE_DIVBYZERO | FE_INVALID)
257 
258 void
tests_start_mpfr(void)259 tests_start_mpfr (void)
260 {
261   /* Don't buffer, so output is not lost if a test causes a segv, etc.
262      For stdout, this is important as it will typically be fully buffered
263      by default with "make check". For stderr, the C standard just says
264      that it is not fully buffered (it may be line buffered by default);
265      disabling buffering completely might be useful in some cases.
266      Warning! No operations must have already been done on stdout/stderr
267      (this is a requirement of ISO C, and this is important on AIX).
268      Thus tests_start_mpfr should be called at the beginning of main(),
269      possibly after some variable settings. */
270   setbuf (stdout, NULL);
271   setbuf (stderr, NULL);
272 
273   test_version ();
274 
275 #if defined HAVE_LOCALE_H && defined HAVE_SETLOCALE
276   /* Added on 2005-07-09. This allows to test MPFR under various
277      locales. New bugs will probably be found, in particular with
278      LC_ALL="tr_TR.ISO8859-9" because of the i/I character... */
279   locale = setlocale (LC_ALL, "");
280 #endif
281 
282 #ifdef MPFR_FPU_PREC
283   set_fpu_prec ();
284 #endif
285 
286 #ifdef MPFR_TESTS_FPE_DIV
287   /* Define to test the use of MPFR_ERRDIVZERO */
288   feclearexcept (FE_ALL_EXCEPT);
289 # ifdef MPFR_TESTS_FPE_TRAP
290   /* to trap the corresponding FP exceptions */
291   feenableexcept (FPE_FLAGS);
292 # endif
293 #endif
294 
295   if (tests_memory_disabled != 2)
296     {
297       if (tests_memory_disabled == 0)
298         tests_memory_start ();
299       tests_rand_start ();
300     }
301   tests_limit_start ();
302 
303   default_emin = mpfr_get_emin ();
304   default_emax = mpfr_get_emax ();
305 }
306 
307 void
tests_end_mpfr(void)308 tests_end_mpfr (void)
309 {
310   int err = 0;
311 
312   if (mpfr_get_emin () != default_emin)
313     {
314       printf ("Default emin value has not been restored!\n");
315       err = 1;
316     }
317 
318   if (mpfr_get_emax () != default_emax)
319     {
320       printf ("Default emax value has not been restored!\n");
321       err = 1;
322     }
323 
324   mpfr_free_cache ();
325   mpfr_free_cache2 (MPFR_FREE_GLOBAL_CACHE);
326   if (tests_memory_disabled != 2)
327     {
328       tests_rand_end ();
329       if (tests_memory_disabled == 0)
330         tests_memory_end ();
331     }
332 
333 #ifdef MPFR_TESTS_FPE_DIV
334   /* Define to test the use of MPFR_ERRDIVZERO */
335   if (fetestexcept (FPE_FLAGS))
336     {
337       /* With MPFR_ERRDIVZERO, such exceptions should never occur
338          because the purpose of defining MPFR_ERRDIVZERO is to avoid
339          all the FP divisions by 0. */
340       printf ("Some floating-point exception(s) occurred:");
341       if (fetestexcept (FE_DIVBYZERO))
342         printf (" DIVBYZERO");  /* e.g. from 1.0 / 0.0 to generate an inf */
343       if (fetestexcept (FE_INVALID))
344         printf (" INVALID");    /* e.g. from 0.0 / 0.0 to generate a NaN */
345       printf ("\n");
346       err = 1;
347     }
348 #endif
349 
350   if (err)
351     exit (err);
352 }
353 
354 static void
tests_limit_start(void)355 tests_limit_start (void)
356 {
357 #ifdef MPFR_TESTS_TIMEOUT
358   struct rlimit rlim[1];
359   char *timeoutp;
360   int timeout;
361 
362   timeoutp = getenv ("MPFR_TESTS_TIMEOUT");
363   timeout = timeoutp != NULL ? atoi (timeoutp) : MPFR_TESTS_TIMEOUT;
364   if (timeout > 0)
365     {
366       /* We need to call getrlimit first to initialize rlim_max to
367          an acceptable value for setrlimit. When enabled, timeouts
368          are regarded as important: we don't want to take too much
369          CPU time on machines shared with other users. So, if we
370          can't set the timeout, we exit immediately. */
371       if (getrlimit (RLIMIT_CPU, rlim))
372         {
373           printf ("Error: getrlimit failed\n");
374           exit (1);
375         }
376       rlim->rlim_cur = timeout;
377       if (setrlimit (RLIMIT_CPU, rlim))
378         {
379           printf ("Error: setrlimit failed\n");
380           exit (1);
381         }
382     }
383 #endif
384 }
385 
386 static void
tests_rand_start(void)387 tests_rand_start (void)
388 {
389   char           *perform_seed;
390   unsigned long  seed;
391 
392   if (mpfr_rands_initialized)
393     {
394       printf (
395         "Please let tests_start() initialize the global mpfr_rands, i.e.\n"
396         "ensure that function is called before the first use of RANDS.\n");
397       exit (1);
398     }
399 
400   gmp_randinit_default (mpfr_rands);
401   mpfr_rands_initialized = 1;
402 
403   perform_seed = getenv ("GMP_CHECK_RANDOMIZE");
404   if (perform_seed != NULL)
405     {
406       seed = strtoul (perform_seed, NULL, 10);
407       if (! (seed == 0 || seed == 1))
408         {
409           printf ("Re-seeding with GMP_CHECK_RANDOMIZE=%lu\n", seed);
410           gmp_randseed_ui (mpfr_rands, seed);
411         }
412       else
413         {
414 #ifdef HAVE_GETTIMEOFDAY
415           struct timeval  tv;
416           gettimeofday (&tv, NULL);
417           /* Note: If time_t is a "floating type" (as allowed by ISO C99),
418              the cast below can yield undefined behavior. But this would
419              be uncommon (gettimeofday() is specified by POSIX only and
420              POSIX requires time_t to be an integer type) and this line
421              is not executed by default. So, this should be OK. Moreover,
422              gettimeofday() is marked obsolescent by POSIX.1-2008. */
423           seed = 1000000 * (unsigned long) tv.tv_sec + tv.tv_usec;
424 #else
425           time_t  tv;
426           time (&tv);
427           seed = tv;
428 #endif
429           gmp_randseed_ui (mpfr_rands, seed);
430           printf ("Seed GMP_CHECK_RANDOMIZE=%lu "
431                   "(include this in bug reports)\n", seed);
432         }
433     }
434   else
435     gmp_randseed_ui (mpfr_rands, 0x2143FEDC);
436 }
437 
438 static void
tests_rand_end(void)439 tests_rand_end (void)
440 {
441   RANDS_CLEAR ();
442 }
443 
444 /* true if subnormals are supported for double */
445 int
have_subnorm_dbl(void)446 have_subnorm_dbl (void)
447 {
448   volatile double x = DBL_MIN, y;
449 
450   y = x / 2.0;
451   return 2.0 * y == x;
452 }
453 
454 /* true if subnormals are supported for float */
455 int
have_subnorm_flt(void)456 have_subnorm_flt (void)
457 {
458   volatile float x = FLT_MIN, y;
459 
460   y = x / 2.0f;
461   return 2.0f * y == x;
462 }
463 
464 /* initialization function for tests using the hardware floats
465    Not very useful now. */
466 void
mpfr_test_init(void)467 mpfr_test_init (void)
468 {
469 #ifdef HAVE_FPC_CSR
470   /* to get subnormal numbers on IRIX64 */
471   union fpc_csr exp;
472 
473   exp.fc_word = get_fpc_csr();
474   exp.fc_struct.flush = 0;
475   set_fpc_csr(exp.fc_word);
476 #endif
477 
478   /* generate DBL_EPSILON with a loop to avoid that the compiler
479      optimizes the code below in non-IEEE 754 mode, deciding that
480      c = d is always false. */
481 #if 0
482   for (eps = 1.0; eps != DBL_EPSILON; eps /= 2.0);
483   c = 1.0 + eps;
484   d = eps * (1.0 - eps) / 2.0;
485   d += c;
486   if (c != d)
487     {
488       printf ("Warning: IEEE 754 standard not fully supported\n"
489               "         (maybe extended precision not disabled)\n"
490               "         Some tests may fail\n");
491     }
492 #endif
493 }
494 
495 
496 /* generate a random limb */
497 mp_limb_t
randlimb(void)498 randlimb (void)
499 {
500   mp_limb_t limb;
501 
502   mpfr_rand_raw (&limb, RANDS, GMP_NUMB_BITS);
503   return limb;
504 }
505 
506 unsigned long
randulong(void)507 randulong (void)
508 {
509 #ifdef MPFR_LONG_WITHIN_LIMB
510 
511   return randlimb ();
512 
513 #else
514 
515   unsigned long u = 0, v = 0;
516 
517   while (u |= randlimb (), v |= MPFR_LIMB_MAX, v != ULONG_MAX)
518     {
519       u <<= GMP_NUMB_BITS;
520       v <<= GMP_NUMB_BITS;
521     }
522 
523   return u;
524 
525 #endif
526 }
527 
528 long
randlong(void)529 randlong (void)
530 {
531   unsigned long u = randulong ();
532 
533   return ULONG2LONG (u);
534 }
535 
536 /* returns ulp(x) for x a 'normal' double-precision number */
537 double
Ulp(double x)538 Ulp (double x)
539 {
540    double y, eps;
541 
542    if (x < 0) x = -x;
543 
544    y = x * 2.220446049250313080847263336181640625e-16 ; /* x / 2^52 */
545 
546    /* as ulp(x) <= y = x/2^52 < 2*ulp(x),
547    we have x + ulp(x) <= x + y <= x + 2*ulp(x),
548    therefore o(x + y) = x + ulp(x) or x + 2*ulp(x) */
549 
550    eps =  x + y;
551    eps = eps - x; /* ulp(x) or 2*ulp(x) */
552 
553    return (eps > y) ? 0.5 * eps : eps;
554 }
555 
556 /* returns the number of ulp's between a and b,
557    where a and b can be any floating-point number, except NaN
558  */
559 int
ulp(double a,double b)560 ulp (double a, double b)
561 {
562   double twoa;
563 
564   if (a == b) return 0; /* also deals with a=b=inf or -inf */
565 
566   twoa = a + a;
567   if (twoa == a) /* a is +/-0.0 or +/-Inf */
568     return ((b < a) ? INT_MAX : -INT_MAX);
569 
570   return (int) ((a - b) / Ulp (a));
571 }
572 
573 /* return double m*2^e */
574 double
dbl(double m,int e)575 dbl (double m, int e)
576 {
577   if (e >=0 )
578     while (e-- > 0)
579       m *= 2.0;
580   else
581     while (e++ < 0)
582       m /= 2.0;
583   return m;
584 }
585 
586 /* Warning: NaN values cannot be distinguished if MPFR_NANISNAN is defined. */
587 int
Isnan(double d)588 Isnan (double d)
589 {
590   return (d) != (d);
591 }
592 
593 void
d_trace(const char * name,double d)594 d_trace (const char *name, double d)
595 {
596   double x = d;
597   unsigned char *p = (unsigned char *) &x;
598   int  i;
599 
600   if (name != NULL && name[0] != '\0')
601     printf ("%s = ", name);
602 
603   printf ("[");
604   for (i = 0; i < (int) sizeof (double); i++)
605     {
606       if (i != 0)
607         printf (" ");
608       printf ("%02X", (unsigned int) p[i]);
609     }
610   printf ("] %.20g\n", d);
611 }
612 
613 void
ld_trace(const char * name,long double ld)614 ld_trace (const char *name, long double ld)
615 {
616   long double x = ld;
617   unsigned char *p = (unsigned char *) &x;
618   int  i;
619 
620   if (name != NULL && name[0] != '\0')
621     printf ("%s = ", name);
622 
623   printf ("[");
624   for (i = 0; i < (int) sizeof (long double); i++)
625     {
626       if (i != 0)
627         printf (" ");
628       printf ("%02X", (unsigned int) p[i]);
629     }
630   printf ("] %.20Lg\n", ld);
631 }
632 
633 void
n_trace(const char * name,mp_limb_t * p,mp_size_t n)634 n_trace (const char *name, mp_limb_t *p, mp_size_t n)
635 {
636   unsigned char *buf;
637   size_t bufsize;
638   mp_size_t i, m;
639 
640   if (name != NULL && name[0] != '\0')
641     printf ("%s=", name);
642 
643   /* similar to gmp_printf ("%NX\n",...), which is not available
644      with mini-gmp */
645   bufsize = 2 + ((mpfr_prec_t) n * GMP_NUMB_BITS - 1) / 4;
646   buf = (unsigned char *) tests_allocate (bufsize);
647   m = mpn_get_str (buf, 16, p, n);
648   i = 0;
649   while (i < m - 1 && buf[i] == 0)
650     i++;  /* skip leading zeros (keeping at least one digit) */
651   while (i < m)
652     putchar ("0123456789ABCDEF"[buf[i++]]);
653   putchar ('\n');
654   tests_free (buf, bufsize);
655 }
656 
657 /* Open a file in the SRCDIR directory, i.e. the "tests" source directory,
658    which is different from the current directory when objdir is different
659    from srcdir. One should generally use this function instead of fopen
660    directly. */
661 FILE *
src_fopen(const char * filename,const char * mode)662 src_fopen (const char *filename, const char *mode)
663 {
664 #ifndef SRCDIR
665   return fopen (filename, mode);
666 #else
667   const char *srcdir = SRCDIR;
668   char *buffer;
669   size_t buffsize;
670   FILE *f;
671 
672   buffsize = strlen (filename) + strlen (srcdir) + 2;
673   buffer = (char *) tests_allocate (buffsize);
674   if (buffer == NULL)
675     {
676       printf ("src_fopen: failed to alloc memory)\n");
677       exit (1);
678     }
679   sprintf (buffer, "%s/%s", srcdir, filename);
680   f = fopen (buffer, mode);
681   tests_free (buffer, buffsize);
682   return f;
683 #endif
684 }
685 
686 void
set_emin(mpfr_exp_t exponent)687 set_emin (mpfr_exp_t exponent)
688 {
689   if (mpfr_set_emin (exponent))
690     {
691       printf ("set_emin: setting emin to %" MPFR_EXP_FSPEC "d failed\n",
692               (mpfr_eexp_t) exponent);
693       exit (1);
694     }
695 }
696 
697 void
set_emax(mpfr_exp_t exponent)698 set_emax (mpfr_exp_t exponent)
699 {
700   if (mpfr_set_emax (exponent))
701     {
702       printf ("set_emax: setting emax to %" MPFR_EXP_FSPEC "d failed\n",
703               (mpfr_eexp_t) exponent);
704       exit (1);
705     }
706 }
707 
708 /* pos is 512 times the proportion of negative numbers.
709    If pos=256, half of the numbers are negative.
710    If pos=0, all generated numbers are positive.
711 */
712 void
tests_default_random(mpfr_ptr x,int pos,mpfr_exp_t emin,mpfr_exp_t emax,int always_scale)713 tests_default_random (mpfr_ptr x, int pos, mpfr_exp_t emin, mpfr_exp_t emax,
714                       int always_scale)
715 {
716   MPFR_ASSERTN (emin <= emax);
717   MPFR_ASSERTN (emin >= MPFR_EMIN_MIN);
718   MPFR_ASSERTN (emax <= MPFR_EMAX_MAX);
719   /* but it isn't required that emin and emax are in the current
720      exponent range (see below), so that underflow/overflow checks
721      can be done on 64-bit machines without a manual change of the
722      exponent range (well, this is a bit ugly...). */
723 
724   mpfr_urandomb (x, RANDS);
725   if (MPFR_IS_PURE_FP (x) && (emin >= 1 || always_scale || RAND_BOOL ()))
726     {
727       mpfr_exp_t e;
728       e = emin + (mpfr_exp_t) (randlimb () % (emax - emin + 1));
729       /* Note: There should be no overflow here because both terms are
730          between MPFR_EMIN_MIN and MPFR_EMAX_MAX. */
731       MPFR_ASSERTD (e >= emin && e <= emax);
732       if (mpfr_set_exp (x, e))
733         {
734           /* The random number doesn't fit in the current exponent range.
735              In this case, test the function in the extended exponent range,
736              which should be restored by the caller. */
737           set_emin (MPFR_EMIN_MIN);
738           set_emax (MPFR_EMAX_MAX);
739           mpfr_set_exp (x, e);
740         }
741     }
742   if (randlimb () % 512 < pos)
743     mpfr_neg (x, x, MPFR_RNDN);
744 }
745 
746 /* If sb = -1, then the function is tested in only one rounding mode
747    (the one provided in rnd) and the ternary value is not checked.
748    Otherwise, the function is tested in the 5 rounding modes, rnd must
749    initially be MPFR_RNDZ, y = RNDZ(f(x)), and sb is 0 if f(x) is exact,
750    1 if f(x) is inexact (in which case, y must be a regular number,
751    i.e. not the result of an overflow or an underflow); the successive
752    rounding modes are:
753      * MPFR_RNDZ, MPFR_RNDD, MPFR_RNDA, MPFR_RNDU, MPFR_RNDN for positive y;
754      * MPFR_RNDZ, MPFR_RNDU, MPFR_RNDA, MPFR_RNDD, MPFR_RNDN for negative y;
755    for the last test MPFR_RNDN, the target precision is decreased by 1 in
756    order to be able to deduce the result (anyway, for a hard-to-round case
757    in directed rounding modes, if yprec is chosen to be minimum precision
758    preserving this hard-to-round case, then one has a hard-to-round case
759    in round-to-nearest for precision yprec-1). If the target precision was
760    MPFR_PREC_MIN, then skip the MPFR_RNDN test; thus to test exact special
761    cases, use a target precision larger than MPFR_PREC_MIN.
762    Note: if y is a regular number, sb corresponds to the sticky bit when
763    considering round-to-nearest with precision yprec-1.
764    As examples of use, see the calls to test5rm from the data_check and
765    bad_cases functions. */
766 static void
test5rm(int (* fct)(FLIST),mpfr_srcptr x,mpfr_ptr y,mpfr_ptr z,mpfr_rnd_t rnd,int sb,const char * name)767 test5rm (int (*fct) (FLIST), mpfr_srcptr x, mpfr_ptr y, mpfr_ptr z,
768          mpfr_rnd_t rnd, int sb, const char *name)
769 {
770   mpfr_prec_t yprec = MPFR_PREC (y);
771   mpfr_rnd_t rndnext = MPFR_RND_MAX;  /* means uninitialized */
772   int expected_inex = INT_MIN;
773 
774   MPFR_ASSERTN (sb == -1 || rnd == MPFR_RNDZ);
775   mpfr_set_prec (z, yprec);
776   while (1)
777     {
778       int inex;
779 
780       MPFR_ASSERTN (rnd != MPFR_RND_MAX);
781       inex = fct (z, x, rnd);
782       if (sb == -1)
783         expected_inex = inex;  /* not checked */
784       else if (rnd != MPFR_RNDN)
785         expected_inex =
786           sb == 0 ? 0 : MPFR_IS_LIKE_RNDD (rnd, MPFR_SIGN (y)) ? -1 : 1;
787       MPFR_ASSERTN (expected_inex != INT_MIN);
788       if (!(SAME_VAL (y, z) && SAME_SIGN (inex, expected_inex)))
789         {
790           printf ("test5rm: error for %s with xprec=%lu, yprec=%lu, rnd=%s\n"
791                   "x = ",
792                   name, (unsigned long) MPFR_PREC (x), (unsigned long) yprec,
793                   mpfr_print_rnd_mode (rnd));
794           mpfr_out_str (stdout, 16, 0, x, MPFR_RNDN);
795           printf ("\nexpected ");
796           mpfr_out_str (stdout, 16, 0, y, MPFR_RNDN);
797           printf ("\ngot      ");
798           mpfr_out_str (stdout, 16, 0, z, MPFR_RNDN);
799           printf ("\n");
800           if (sb != -1)
801             printf ("Expected inex = %d, got %d\n", expected_inex, inex);
802           exit (1);
803         }
804 
805       if (sb == -1 || rnd == MPFR_RNDN)
806         break;
807       else if (rnd == MPFR_RNDZ)
808         {
809           rnd = MPFR_IS_NEG (y) ? MPFR_RNDU : MPFR_RNDD;
810           rndnext = MPFR_RNDA;
811         }
812       else
813         {
814           rnd = rndnext;
815           if (rnd == MPFR_RNDA)
816             {
817               if (sb)
818                 mpfr_nexttoinf (y);
819               rndnext = MPFR_IS_NEG (y) ? MPFR_RNDD : MPFR_RNDU;
820             }
821           else if (rndnext != MPFR_RNDN)
822             rndnext = MPFR_RNDN;
823           else
824             {
825               if (yprec == MPFR_PREC_MIN)
826                 break;
827               /* If sb = 1, then mpfr_nexttoinf was called on y for the
828                  MPFR_RNDA test, i.e. y = RNDA(yprec,f(x)); we use MPFR_RNDZ
829                  since one has the property RNDN(p,w) = RNDZ(p,RNDA(p+1,w))
830                  when w is not a midpoint in precision p. If sb = 0, then
831                  y = f(x), so that RNDN(yprec-1,f(x)) = RNDN(yprec-1,y). */
832               inex = mpfr_prec_round (y, --yprec, sb ? MPFR_RNDZ : MPFR_RNDN);
833               expected_inex = sb ?
834                 MPFR_SIGN (y) * (inex == 0 ? 1 : -1) : inex;
835               mpfr_set_prec (z, yprec);
836             }
837         }
838     }
839 }
840 
841 /* Check data in file f for function foo, with name 'name'.
842    Each line consists of the file f one:
843 
844    xprec yprec rnd x y
845 
846    where:
847 
848    xprec is the input precision
849    yprec is the output precision
850    rnd is the rounding mode (n, z, u, d, a, Z, *)
851    x is the input (hexadecimal format)
852    y is the expected output (hexadecimal format) for foo(x) with rounding rnd
853 
854    If rnd is Z, then y is the expected output in round-toward-zero and
855    it is assumed to be inexact; the four directed rounding modes are
856    tested, and the round-to-nearest mode is tested in precision yprec-1.
857    See details in the description of test5rm above.
858 
859    If rnd is *, y must be an exact case (possibly a special case).
860    All the rounding modes are tested and the ternary value is checked
861    (it must be 0).
862  */
863 void
data_check(const char * f,int (* foo)(FLIST),const char * name)864 data_check (const char *f, int (*foo) (FLIST), const char *name)
865 {
866   FILE *fp;
867   long int xprec, yprec;  /* not mpfr_prec_t because of the fscanf */
868   mpfr_t x, y, z;
869   mpfr_rnd_t rnd;
870   char r;
871   int c;
872 
873   fp = fopen (f, "r");
874   if (fp == NULL)
875     fp = src_fopen (f, "r");
876   if (fp == NULL)
877     {
878       char *v = (char *) MPFR_VERSION_STRING;
879 
880       /* In the '-dev' versions, assume that the data file exists and
881          return an error if the file cannot be opened to make sure
882          that such failures are detected. */
883       while (*v != '\0')
884         v++;
885       if (v[-4] == '-' && v[-3] == 'd' && v[-2] == 'e' && v[-1] == 'v')
886         {
887           printf ("Error: unable to open file '%s'\n", f);
888           exit (1);
889         }
890       else
891         return;
892     }
893 
894   mpfr_init (x);
895   mpfr_init (y);
896   mpfr_init (z);
897 
898   while (!feof (fp))
899     {
900       /* skip whitespace, for consistency */
901       if (fscanf (fp, " ") == EOF)
902         {
903           if (ferror (fp))
904             {
905               perror ("data_check");
906               exit (1);
907             }
908           else
909             break;  /* end of file */
910         }
911 
912       if ((c = getc (fp)) == EOF)
913         {
914           if (ferror (fp))
915             {
916               perror ("data_check");
917               exit (1);
918             }
919           else
920             break;  /* end of file */
921         }
922 
923       if (c == '#') /* comment: read entire line */
924         {
925           do
926             {
927               c = getc (fp);
928             }
929           while (!feof (fp) && c != '\n');
930         }
931       else
932         {
933           ungetc (c, fp);
934 
935           c = fscanf (fp, "%ld %ld %c", &xprec, &yprec, &r);
936           MPFR_ASSERTN (MPFR_PREC_COND (xprec));
937           MPFR_ASSERTN (MPFR_PREC_COND (yprec));
938           if (c == EOF)
939             {
940               perror ("data_check");
941               exit (1);
942             }
943           else if (c != 3)
944             {
945               printf ("Error: corrupted line in file '%s'\n", f);
946               exit (1);
947             }
948 
949           switch (r)
950             {
951             case 'n':
952               rnd = MPFR_RNDN;
953               break;
954             case 'z': case 'Z':
955               rnd = MPFR_RNDZ;
956               break;
957             case 'u':
958               rnd = MPFR_RNDU;
959               break;
960             case 'd':
961               rnd = MPFR_RNDD;
962               break;
963             case '*':
964               rnd = MPFR_RND_MAX; /* non-existing rounding mode */
965               break;
966             default:
967               printf ("Error: unexpected rounding mode"
968                       " in file '%s': %c\n", f, (int) r);
969               exit (1);
970             }
971           mpfr_set_prec (x, xprec);
972           mpfr_set_prec (y, yprec);
973           if (mpfr_inp_str (x, fp, 0, MPFR_RNDN) == 0)
974             {
975               printf ("Error: corrupted argument in file '%s'\n", f);
976               exit (1);
977             }
978           if (mpfr_inp_str (y, fp, 0, MPFR_RNDN) == 0)
979             {
980               printf ("Error: corrupted result in file '%s'\n", f);
981               exit (1);
982             }
983           if (getc (fp) != '\n')
984             {
985               printf ("Error: result not followed by \\n in file '%s'\n", f);
986               exit (1);
987             }
988           /* Skip whitespace, in particular at the end of the file. */
989           if (fscanf (fp, " ") == EOF && ferror (fp))
990             {
991               perror ("data_check");
992               exit (1);
993             }
994           if (r == '*')
995             test5rm (foo, x, y, z, MPFR_RNDZ, 0, name);
996           else
997             test5rm (foo, x, y, z, rnd, r == 'Z' ? 1 : -1, name);
998         }
999     }
1000 
1001   mpfr_clear (x);
1002   mpfr_clear (y);
1003   mpfr_clear (z);
1004 
1005   fclose (fp);
1006 }
1007 
1008 /* Test n random bad cases. A precision py in [pymin,pymax] and
1009  * a number y of precision py are chosen randomly. One computes
1010  * x = inv(y) in precision px = py + psup (rounded to nearest).
1011  * Then (in general), y is a bad case for fct in precision py (in
1012  * the directed rounding modes, but also in the rounding-to-nearest
1013  * mode for some lower precision: see data_check).
1014  * fct, inv, name: data related to the function.
1015  * pos, emin, emax: arguments for tests_default_random.
1016  * For debugging purpose (e.g. in case of crash or infinite loop),
1017  * you can set the MPFR_DEBUG_BADCASES environment variable to 1 in
1018  * order to output information about the tested worst cases. You can
1019  * also enable logging (when supported), but this may give too much
1020  * information.
1021  */
1022 void
bad_cases(int (* fct)(FLIST),int (* inv)(FLIST),const char * name,int pos,mpfr_exp_t emin,mpfr_exp_t emax,mpfr_prec_t pymin,mpfr_prec_t pymax,mpfr_prec_t psup,int n)1023 bad_cases (int (*fct)(FLIST), int (*inv)(FLIST), const char *name,
1024            int pos, mpfr_exp_t emin, mpfr_exp_t emax,
1025            mpfr_prec_t pymin, mpfr_prec_t pymax, mpfr_prec_t psup,
1026            int n)
1027 {
1028   mpfr_t x, y, z;
1029   char *dbgenv;
1030   int cnt = 0, i, dbg;
1031   mpfr_exp_t old_emin, old_emax;
1032 
1033   old_emin = mpfr_get_emin ();
1034   old_emax = mpfr_get_emax ();
1035 
1036   dbgenv = getenv ("MPFR_DEBUG_BADCASES");
1037   dbg = dbgenv != 0 ? atoi (dbgenv) : 0;  /* debug level */
1038   mpfr_inits2 (MPFR_PREC_MIN, x, y, z, (mpfr_ptr) 0);
1039   for (i = 0; i < n; i++)
1040     {
1041       mpfr_prec_t px, py, pz;
1042       int inex_inv, inex, sb;
1043 
1044       if (dbg)
1045         printf ("bad_cases: %s, i = %d\n", name, i);
1046       py = pymin + (randlimb () % (pymax - pymin + 1));
1047       mpfr_set_prec (y, py);
1048       tests_default_random (y, pos, emin, emax, 0);
1049       if (dbg)
1050         {
1051           printf ("bad_cases: yprec =%4ld, y = ", (long) py);
1052           mpfr_out_str (stdout, 16, 0, y, MPFR_RNDN);
1053           printf ("\n");
1054         }
1055       px = py + psup;
1056       mpfr_set_prec (x, px);
1057       if (dbg)
1058         printf ("bad_cases: xprec =%4ld\n", (long) px);
1059       mpfr_clear_flags ();
1060       inex_inv = inv (x, y, MPFR_RNDN);
1061       if (mpfr_nanflag_p () || mpfr_overflow_p () || mpfr_underflow_p ())
1062         {
1063           if (dbg)
1064             printf ("bad_cases: no normal inverse\n");
1065           goto next_i;
1066         }
1067       if (dbg > 1)
1068         {
1069           printf ("bad_cases: x = ");
1070           mpfr_out_str (stdout, 16, 0, x, MPFR_RNDN);
1071           printf ("\n");
1072         }
1073       pz = px;
1074       do
1075         {
1076           pz += 32;
1077           mpfr_set_prec (z, pz);
1078           sb = fct (z, x, MPFR_RNDN) != 0;
1079           if (!sb)
1080             {
1081               if (dbg)
1082                 {
1083                   printf ("bad_cases: exact case z = ");
1084                   mpfr_out_str (stdout, 16, 0, z, MPFR_RNDN);
1085                   printf ("\n");
1086                 }
1087               if (inex_inv)
1088                 {
1089                   printf ("bad_cases: f exact while f^(-1) inexact,\n"
1090                           "due to a poor choice of the parameters.\n");
1091                   exit (1);
1092                   /* alternatively, goto next_i */
1093                 }
1094               inex = 0;
1095               break;
1096             }
1097           if (dbg)
1098             {
1099               if (dbg > 1)
1100                 {
1101                   printf ("bad_cases: %s(x) ~= ", name);
1102                   mpfr_out_str (stdout, 16, 0, z, MPFR_RNDN);
1103                 }
1104               else
1105                 {
1106                   printf ("bad_cases:   [MPFR_RNDZ]  ~= ");
1107                   mpfr_out_str (stdout, 16, 40, z, MPFR_RNDZ);
1108                 }
1109               printf ("\n");
1110             }
1111           inex = mpfr_prec_round (z, py, MPFR_RNDN);
1112           if (mpfr_nanflag_p () || mpfr_overflow_p () || mpfr_underflow_p ()
1113               || ! mpfr_equal_p (z, y))
1114             {
1115               if (dbg)
1116                 {
1117                   printf ("bad_cases: inverse doesn't match for %s\ny = ",
1118                           name);
1119                   mpfr_out_str (stdout, 16, 0, y, MPFR_RNDN);
1120                   printf ("\nz = ");
1121                   mpfr_out_str (stdout, 16, 0, z, MPFR_RNDN);
1122                   printf ("\n");
1123                 }
1124               goto next_i;
1125             }
1126         }
1127       while (inex == 0);
1128       /* We really have a bad case (or some special case). */
1129       if (mpfr_zero_p (z))
1130         {
1131           /* This can occur on tlog (GMP_CHECK_RANDOMIZE=1630879377004032
1132              in r14570, 2021-09-07):
1133              y = -0, giving x = 1 and z = 0. We have y = z, but here,
1134              y and z have different signs. Since test5rm will test f(x)
1135              and its sign (in particular for 0), we need to take the
1136              sign of f(x), i.e. of z.
1137              Note: To avoid this special case, one might want to detect and
1138              ignore y = 0 (of any sign) when taking the random number above,
1139              as this case should be redundant with some other tests. */
1140           mpfr_set (y, z, MPFR_RNDN);
1141           py = MPFR_PREC_MIN;
1142         }
1143       else
1144         {
1145           do
1146             py--;
1147           while (py >= MPFR_PREC_MIN &&
1148                  mpfr_prec_round (z, py, MPFR_RNDZ) == 0);
1149           py++;
1150         }
1151       /* py is now the smallest output precision such that we have
1152          a bad case in the directed rounding modes. */
1153       if (mpfr_prec_round (y, py, MPFR_RNDZ) != 0)
1154         {
1155           printf ("Internal error for i = %d\n", i);
1156           exit (1);
1157         }
1158       if ((inex > 0 && MPFR_IS_POS (z)) ||
1159           (inex < 0 && MPFR_IS_NEG (z)))
1160         {
1161           mpfr_nexttozero (y);
1162           if (mpfr_zero_p (y))
1163             goto next_i;
1164         }
1165       if (dbg)
1166         {
1167           printf ("bad_cases: yprec =%4ld, y = ", (long) py);
1168           mpfr_out_str (stdout, 16, 0, y, MPFR_RNDN);
1169           printf ("\n");
1170         }
1171       /* Note: y is now the expected result rounded toward zero. */
1172       test5rm (fct, x, y, z, MPFR_RNDZ, sb, name);
1173       cnt++;
1174     next_i:
1175       /* In case the exponent range has been changed by
1176          tests_default_random()... */
1177       set_emin (old_emin);
1178       set_emax (old_emax);
1179     }
1180   mpfr_clears (x, y, z, (mpfr_ptr) 0);
1181 
1182   if (dbg)
1183     printf ("bad_cases: %d bad cases over %d generated values for %s\n",
1184             cnt, n, name);
1185 
1186   if (getenv ("MPFR_CHECK_BADCASES") && n - cnt > n/10)
1187     {
1188       printf ("bad_cases: too few bad cases (%d over %d generated values)"
1189               " for %s\n", cnt, n, name);
1190       exit (1);
1191     }
1192 }
1193 
1194 void
flags_out(unsigned int flags)1195 flags_out (unsigned int flags)
1196 {
1197   int none = 1;
1198 
1199   if (flags & MPFR_FLAGS_UNDERFLOW)
1200     none = 0, printf (" underflow");
1201   if (flags & MPFR_FLAGS_OVERFLOW)
1202     none = 0, printf (" overflow");
1203   if (flags & MPFR_FLAGS_NAN)
1204     none = 0, printf (" nan");
1205   if (flags & MPFR_FLAGS_INEXACT)
1206     none = 0, printf (" inexact");
1207   if (flags & MPFR_FLAGS_ERANGE)
1208     none = 0, printf (" erange");
1209   if (none)
1210     printf (" none");
1211   printf (" (%u)\n", flags);
1212 }
1213 
1214 static void
abort_called(int x)1215 abort_called (int x)
1216 {
1217   /* Ok, abort has been called */
1218   exit (0);
1219 }
1220 
1221 /* This function has to be called for a test
1222    that will call the abort function */
1223 void
tests_expect_abort(void)1224 tests_expect_abort (void)
1225 {
1226 #if defined(HAVE_SIGACTION)
1227   struct sigaction act;
1228   int ret;
1229 
1230   memset (&act, 0, sizeof act);
1231   act.sa_handler = abort_called;
1232   ret = sigaction (SIGABRT, &act, NULL);
1233   if (ret != 0)
1234     {
1235       /* Can't register error handler: Skip test */
1236       exit (77);
1237     }
1238 #elif defined(HAVE_SIGNAL)
1239   signal (SIGABRT, abort_called);
1240 #else
1241   /* Can't register error handler: Skip test */
1242   exit (77);
1243 #endif
1244 }
1245 
1246 /* Guess whether the test runs within Valgrind.
1247    Note: This should work at least under Linux and Solaris.
1248    If need be, support for macOS (with DYLD_INSERT_LIBRARIES) and
1249    i386 FreeBSD on amd64 (with LD_32_PRELOAD) could be added; thanks
1250    to Paul Floyd for the information.
1251    Up-to-date information should be found at
1252    <https://stackoverflow.com/a/62364698/3782797>. */
1253 int
tests_run_within_valgrind(void)1254 tests_run_within_valgrind (void)
1255 {
1256   char *p;
1257 
1258   p = getenv ("LD_PRELOAD");
1259   if (p == NULL)
1260     return 0;
1261   return (strstr (p, "/valgrind/") != NULL ||
1262           strstr (p, "/vgpreload") != NULL);
1263 }
1264