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