1 /* tprintf.c -- test file for mpfr_printf and mpfr_vprintf 2 3 Copyright 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. 4 Contributed by the AriC and Caramel 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 http://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 #if HAVE_STDARG 24 #include <stdarg.h> 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <stddef.h> 29 30 #include "mpfr-intmax.h" 31 #include "mpfr-test.h" 32 #define STDOUT_FILENO 1 33 34 #if MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0) 35 36 #define QUOTE(X) NAME(X) 37 #define NAME(X) #X 38 39 /* unlike other tests, we print out errors to stderr because stdout might be 40 redirected */ 41 #define check_length(num_test, var, value, var_spec) \ 42 if ((var) != (value)) \ 43 { \ 44 fprintf (stderr, "Error in test #%d: mpfr_printf printed %" \ 45 QUOTE(var_spec)" characters instead of %d\n", \ 46 (num_test), (var), (value)); \ 47 exit (1); \ 48 } 49 50 #define check_length_with_cmp(num_test, var, value, cmp, var_spec) \ 51 if (cmp != 0) \ 52 { \ 53 mpfr_fprintf (stderr, "Error in test #%d, mpfr_printf printed %" \ 54 QUOTE(var_spec)" characters instead of %d\n", \ 55 (num_test), (var), (value)); \ 56 exit (1); \ 57 } 58 59 /* limit for random precision in random() */ 60 const int prec_max_printf = 5000; 61 /* boolean: is stdout redirected to a file ? */ 62 int stdout_redirect; 63 64 static void 65 check (const char *fmt, mpfr_t x) 66 { 67 if (mpfr_printf (fmt, x) == -1) 68 { 69 fprintf (stderr, "Error in mpfr_printf(\"%s\", ...)\n", fmt); 70 71 exit (1); 72 } 73 putchar ('\n'); 74 } 75 76 static void 77 check_vprintf (const char *fmt, ...) 78 { 79 va_list ap; 80 81 va_start (ap, fmt); 82 if (mpfr_vprintf (fmt, ap) == -1) 83 { 84 fprintf (stderr, "Error in mpfr_vprintf(\"%s\", ...)\n", fmt); 85 86 va_end (ap); 87 exit (1); 88 } 89 putchar ('\n'); 90 va_end (ap); 91 } 92 93 static void 94 check_vprintf_failure (const char *fmt, ...) 95 { 96 va_list ap; 97 98 va_start (ap, fmt); 99 if (mpfr_vprintf (fmt, ap) != -1) 100 { 101 putchar ('\n'); 102 fprintf (stderr, "Error in mpfr_vprintf(\"%s\", ...)\n", fmt); 103 104 va_end (ap); 105 exit (1); 106 } 107 putchar ('\n'); 108 va_end (ap); 109 } 110 111 static void 112 check_invalid_format (void) 113 { 114 int i = 0; 115 116 /* format in disorder */ 117 check_vprintf_failure ("blah %l2.1d blah", i); 118 check_vprintf_failure ("blah %2.1#d blah", i); 119 120 /* incomplete format */ 121 check_vprintf_failure ("%", i); 122 check_vprintf_failure ("% (missing conversion specifier)", i); 123 check_vprintf_failure ("missing conversion specifier %h", i); 124 check_vprintf_failure ("this should fail %.l because of missing conversion specifier " 125 "(or doubling %%)", i); 126 check_vprintf_failure ("%L", i); 127 check_vprintf_failure ("%hh. ", i); 128 check_vprintf_failure ("blah %j."); 129 check_vprintf_failure ("%ll blah"); 130 check_vprintf_failure ("blah%t blah"); 131 check_vprintf_failure ("%z "); 132 check_vprintf_failure ("%F (missing conversion specifier)"); 133 check_vprintf_failure ("%Q (missing conversion specifier)"); 134 check_vprintf_failure ("%M (missing conversion specifier)"); 135 check_vprintf_failure ("%N (missing conversion specifier)"); 136 check_vprintf_failure ("%Z (missing conversion specifier)"); 137 check_vprintf_failure ("%R (missing conversion specifier)"); 138 check_vprintf_failure ("%R"); 139 check_vprintf_failure ("%P (missing conversion specifier)"); 140 141 /* conversion specifier with wrong length specifier */ 142 check_vprintf_failure ("%ha", i); 143 check_vprintf_failure ("%hhe", i); 144 check_vprintf_failure ("%jf", i); 145 check_vprintf_failure ("%lg", i); 146 check_vprintf_failure ("%tA", i); 147 check_vprintf_failure ("%zE", i); 148 check_vprintf_failure ("%Ld", i); 149 check_vprintf_failure ("%Qf", i); 150 check_vprintf_failure ("%MG", i); 151 check_vprintf_failure ("%Na", i); 152 check_vprintf_failure ("%ZE", i); 153 check_vprintf_failure ("%PG", i); 154 check_vprintf_failure ("%Fu", i); 155 check_vprintf_failure ("%Rx", i); 156 } 157 158 static void 159 check_long_string (void) 160 { 161 /* this test is VERY expensive both in time (~1 min on core2 @ 2.40GHz) and 162 in memory (~2.5 GB) */ 163 mpfr_t x; 164 165 mpfr_init2 (x, INT_MAX); 166 167 mpfr_set_ui (x, 1, MPFR_RNDN); 168 mpfr_nextabove (x); 169 170 check_vprintf_failure ("%Rb", x); 171 check_vprintf_failure ("%RA %RA %Ra %Ra", x, x, x, x); 172 173 mpfr_clear (x); 174 } 175 176 static void 177 check_special (void) 178 { 179 mpfr_t x; 180 181 mpfr_init (x); 182 183 mpfr_set_inf (x, 1); 184 check ("%Ra", x); 185 check ("%Rb", x); 186 check ("%Re", x); 187 check ("%Rf", x); 188 check ("%Rg", x); 189 check_vprintf ("%Ra", x); 190 check_vprintf ("%Rb", x); 191 check_vprintf ("%Re", x); 192 check_vprintf ("%Rf", x); 193 check_vprintf ("%Rg", x); 194 195 mpfr_set_inf (x, -1); 196 check ("%Ra", x); 197 check ("%Rb", x); 198 check ("%Re", x); 199 check ("%Rf", x); 200 check ("%Rg", x); 201 check_vprintf ("%Ra", x); 202 check_vprintf ("%Rb", x); 203 check_vprintf ("%Re", x); 204 check_vprintf ("%Rf", x); 205 check_vprintf ("%Rg", x); 206 207 mpfr_set_nan (x); 208 check ("%Ra", x); 209 check ("%Rb", x); 210 check ("%Re", x); 211 check ("%Rf", x); 212 check ("%Rg", x); 213 check_vprintf ("%Ra", x); 214 check_vprintf ("%Rb", x); 215 check_vprintf ("%Re", x); 216 check_vprintf ("%Rf", x); 217 check_vprintf ("%Rg", x); 218 219 mpfr_clear (x); 220 } 221 222 static void 223 check_mixed (void) 224 { 225 int ch = 'a'; 226 #ifndef NPRINTF_HH 227 signed char sch = -1; 228 unsigned char uch = 1; 229 #endif 230 short sh = -1; 231 unsigned short ush = 1; 232 int i = -1; 233 int j = 1; 234 unsigned int ui = 1; 235 long lo = -1; 236 unsigned long ulo = 1; 237 float f = -1.25; 238 double d = -1.25; 239 #if !defined(NPRINTF_T) || !defined(NPRINTF_L) 240 long double ld = -1.25; 241 #endif 242 243 #ifndef NPRINTF_T 244 ptrdiff_t p = 1, saved_p; 245 #endif 246 size_t sz = 1; 247 248 mpz_t mpz; 249 mpq_t mpq; 250 mpf_t mpf; 251 mpfr_rnd_t rnd = MPFR_RNDN; 252 253 mpfr_t mpfr; 254 mpfr_prec_t prec; 255 256 mpz_init (mpz); 257 mpz_set_ui (mpz, ulo); 258 mpq_init (mpq); 259 mpq_set_si (mpq, lo, ulo); 260 mpf_init (mpf); 261 mpf_set_q (mpf, mpq); 262 mpfr_init (mpfr); 263 mpfr_set_f (mpfr, mpf, MPFR_RNDN); 264 prec = mpfr_get_prec (mpfr); 265 266 check_vprintf ("a. %Ra, b. %u, c. %lx%n", mpfr, ui, ulo, &j); 267 check_length (1, j, 22, d); 268 check_vprintf ("a. %c, b. %Rb, c. %u, d. %li%ln", i, mpfr, i, lo, &ulo); 269 check_length (2, ulo, 36, lu); 270 check_vprintf ("a. %hi, b. %*f, c. %Re%hn", ush, 3, f, mpfr, &ush); 271 check_length (3, ush, 29, hu); 272 check_vprintf ("a. %hi, b. %f, c. %#.2Rf%n", sh, d, mpfr, &i); 273 check_length (4, i, 29, d); 274 check_vprintf ("a. %R*A, b. %Fe, c. %i%zn", rnd, mpfr, mpf, sz, &sz); 275 check_length (5, (unsigned long) sz, 34, lu); /* no format specifier '%zu' in C89 */ 276 check_vprintf ("a. %Pu, b. %c, c. %RUG, d. %Zi%Zn", prec, ch, mpfr, mpz, &mpz); 277 check_length_with_cmp (6, mpz, 24, mpz_cmp_ui (mpz, 24), Zi); 278 check_vprintf ("%% a. %#.0RNg, b. %Qx%Rn c. %p", 279 mpfr, mpq, &mpfr, (void *) &i); 280 check_length_with_cmp (7, mpfr, 15, mpfr_cmp_ui (mpfr, 15), Rg); 281 282 #ifndef NPRINTF_T 283 saved_p = p; 284 check_vprintf ("%% a. %RNg, b. %Qx, c. %td%tn", mpfr, mpq, p, &p); 285 if (p != 20) 286 mpfr_fprintf (stderr, "Error in test 8, got '%% a. %RNg, b. %Qx, c. %td'\n", mpfr, mpq, saved_p); 287 check_length (8, (long) p, 20, ld); /* no format specifier '%td' in C89 */ 288 #endif 289 290 #ifndef NPRINTF_L 291 check_vprintf ("a. %RA, b. %Lf, c. %QX%zn", mpfr, ld, mpq, &sz); 292 check_length (9, (unsigned long) sz, 30, lu); /* no format specifier '%zu' in C89 */ 293 #endif 294 295 #ifndef NPRINTF_HH 296 check_vprintf ("a. %hhi, b. %Ra, c. %hhu%hhn", sch, mpfr, uch, &uch); 297 check_length (10, (unsigned int) uch, 22, u); /* no format specifier '%hhu' in C89 */ 298 #endif 299 300 #if defined(HAVE_LONG_LONG) && !defined(NPRINTF_LL) 301 { 302 long long llo = -1; 303 unsigned long long ullo = 1; 304 305 check_vprintf ("a. %Re, b. %llx%Qn", mpfr, ullo, &mpq); 306 check_length_with_cmp (11, mpq, 16, mpq_cmp_ui (mpq, 16, 1), Qu); 307 check_vprintf ("a. %lli, b. %Rf%lln", llo, mpfr, &ullo); 308 check_length (12, ullo, 19, llu); 309 } 310 #endif 311 312 #if defined(_MPFR_H_HAVE_INTMAX_T) && !defined(NPRINTF_J) 313 { 314 intmax_t im = -1; 315 uintmax_t uim = 1; 316 317 check_vprintf ("a. %*RA, b. %ji%Fn", 10, mpfr, im, &mpf); 318 check_length_with_cmp (31, mpf, 20, mpf_cmp_ui (mpf, 20), Fg); 319 check_vprintf ("a. %.*Re, b. %jx%jn", 10, mpfr, uim, &im); 320 check_length (32, (long) im, 25, li); /* no format specifier "%ji" in C89 */ 321 } 322 #endif 323 324 mpfr_clear (mpfr); 325 mpf_clear (mpf); 326 mpq_clear (mpq); 327 mpz_clear (mpz); 328 } 329 330 static void 331 check_random (int nb_tests) 332 { 333 int i; 334 mpfr_t x; 335 mpfr_rnd_t rnd; 336 char flag[] = 337 { 338 '-', 339 '+', 340 ' ', 341 '#', 342 '0', /* no ambiguity: first zeros are flag zero*/ 343 '\'' 344 }; 345 char specifier[] = 346 { 347 'a', 348 'b', 349 'e', 350 'f', 351 'g' 352 }; 353 mpfr_exp_t old_emin, old_emax; 354 355 old_emin = mpfr_get_emin (); 356 old_emax = mpfr_get_emax (); 357 358 mpfr_init (x); 359 360 for (i = 0; i < nb_tests; ++i) 361 { 362 int ret; 363 int j, jmax; 364 int spec, prec; 365 #define FMT_SIZE 13 366 char fmt[FMT_SIZE]; /* at most something like "%-+ #0'.*R*f" */ 367 char *ptr = fmt; 368 369 tests_default_random (x, 256, MPFR_EMIN_MIN, MPFR_EMAX_MAX); 370 rnd = (mpfr_rnd_t) RND_RAND (); 371 372 spec = (int) (randlimb () % 5); 373 jmax = (spec == 3 || spec == 4) ? 6 : 5; /* ' flag only with %f or %g */ 374 /* advantage small precision */ 375 prec = (randlimb () % 2) ? 10 : prec_max_printf; 376 prec = (int) (randlimb () % prec); 377 if (spec == 3 378 && (mpfr_get_exp (x) > prec_max_printf 379 || mpfr_get_exp (x) < -prec_max_printf)) 380 /* change style 'f' to style 'e' when number x is very large or very 381 small*/ 382 --spec; 383 384 *ptr++ = '%'; 385 for (j = 0; j < jmax; j++) 386 { 387 if (randlimb () % 3 == 0) 388 *ptr++ = flag[j]; 389 } 390 *ptr++ = '.'; 391 *ptr++ = '*'; 392 *ptr++ = 'R'; 393 *ptr++ = '*'; 394 *ptr++ = specifier[spec]; 395 *ptr = '\0'; 396 MPFR_ASSERTD (ptr - fmt < FMT_SIZE); 397 398 mpfr_printf ("mpfr_printf(\"%s\", %d, %s, %Re)\n", fmt, prec, 399 mpfr_print_rnd_mode (rnd), x); 400 ret = mpfr_printf (fmt, prec, rnd, x); 401 if (ret == -1) 402 { 403 if (spec == 3 404 && (MPFR_GET_EXP (x) > INT_MAX || MPFR_GET_EXP (x) < -INT_MAX)) 405 /* normal failure: x is too large to be output with full precision */ 406 { 407 mpfr_printf ("too large !"); 408 } 409 else 410 { 411 printf ("Error in mpfr_printf(\"%s\", %d, %s, ...)", 412 fmt, prec, mpfr_print_rnd_mode (rnd)); 413 414 if (stdout_redirect) 415 { 416 if ((fflush (stdout) == EOF) || (fclose (stdout) == -1)) 417 { 418 perror ("check_random"); 419 exit (1); 420 } 421 } 422 exit (1); 423 } 424 } 425 putchar ('\n'); 426 } 427 428 mpfr_set_emin (old_emin); 429 mpfr_set_emax (old_emax); 430 431 mpfr_clear (x); 432 } 433 434 int 435 main (int argc, char *argv[]) 436 { 437 int N; 438 439 tests_start_mpfr (); 440 441 /* with no argument: prints to /dev/null, 442 tprintf N: prints N tests to stdout */ 443 if (argc == 1) 444 { 445 N = 1000; 446 stdout_redirect = 1; 447 if (freopen ("/dev/null", "w", stdout) == NULL) 448 { 449 /* We failed to open this device, try with a dummy file */ 450 if (freopen ("mpfrtest.txt", "w", stdout) == NULL) 451 { 452 /* Output the error message to stderr since it is not 453 a message about a wrong result in MPFR. Anyway the 454 stdandard output may have changed. */ 455 fprintf (stderr, "Can't open /dev/null or a temporary file\n"); 456 exit (1); 457 } 458 } 459 } 460 else 461 { 462 stdout_redirect = 0; 463 N = atoi (argv[1]); 464 } 465 466 check_invalid_format (); 467 check_special (); 468 check_mixed (); 469 470 /* expensive tests */ 471 if (getenv ("MPFR_CHECK_LARGEMEM") != NULL) 472 check_long_string(); 473 474 check_random (N); 475 476 if (stdout_redirect) 477 { 478 if ((fflush (stdout) == EOF) || (fclose (stdout) == -1)) 479 perror ("main"); 480 } 481 tests_end_mpfr (); 482 return 0; 483 } 484 485 #else /* MPFR_VERSION */ 486 487 int 488 main (void) 489 { 490 printf ("Warning! Test disabled for this MPFR version.\n"); 491 return 0; 492 } 493 494 #endif /* MPFR_VERSION */ 495 496 #else /* HAVE_STDARG */ 497 498 int 499 main (void) 500 { 501 /* We have nothing to test. */ 502 return 77; 503 } 504 505 #endif /* HAVE_STDARG */ 506