1/* Miscellaneous support for test programs.
2
3Copyright 2001-2023 Free Software Foundation, Inc.
4Contributed by the AriC and Caramba projects, INRIA.
5
6This file is part of the GNU MPFR Library.
7
8The GNU MPFR Library is free software; you can redistribute it and/or modify
9it under the terms of the GNU Lesser General Public License as published by
10the Free Software Foundation; either version 3 of the License, or (at your
11option) any later version.
12
13The GNU MPFR Library is distributed in the hope that it will be useful, but
14WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16License for more details.
17
18You should have received a copy of the GNU Lesser General Public License
19along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
20https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
2151 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
95static void
96set_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
108char             mpfr_rands_initialized = 0;
109gmp_randstate_t  mpfr_rands;
110
111char *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 */
117int tests_memory_disabled = 1;
118#else
119int tests_memory_disabled = 0;
120#endif
121
122static mpfr_exp_t default_emin, default_emax;
123
124static void tests_rand_start (void);
125static void tests_rand_end   (void);
126static 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
132extern void (*dummy_func) (mpfr_srcptr);
133void (*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. */
145int
146test_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
258void
259tests_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
307void
308tests_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
354static void
355tests_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
386static void
387tests_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
438static void
439tests_rand_end (void)
440{
441  RANDS_CLEAR ();
442}
443
444/* true if subnormals are supported for double */
445int
446have_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 */
455int
456have_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. */
466void
467mpfr_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 */
497mp_limb_t
498randlimb (void)
499{
500  mp_limb_t limb;
501
502  mpfr_rand_raw (&limb, RANDS, GMP_NUMB_BITS);
503  return limb;
504}
505
506unsigned long
507randulong (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
528long
529randlong (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 */
537double
538Ulp (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 */
559int
560ulp (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 */
574double
575dbl (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. */
587int
588Isnan (double d)
589{
590  return (d) != (d);
591}
592
593void
594d_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
613void
614ld_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
633void
634n_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. */
661FILE *
662src_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
686void
687set_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
697void
698set_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*/
712void
713tests_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. */
766static void
767test5rm (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 */
863void
864data_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 */
1022void
1023bad_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
1194void
1195flags_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
1214static void
1215abort_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 */
1223void
1224tests_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>. */
1253int
1254tests_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