1/* tprintf.c -- test file for mpfr_printf and mpfr_vprintf 2 3Copyright 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. 4Contributed by the AriC and Caramel 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 20http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., 2151 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() */ 60const int prec_max_printf = 5000; 61/* boolean: is stdout redirected to a file ? */ 62int stdout_redirect; 63 64static void 65check (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 76static void 77check_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 93static void 94check_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 111static void 112check_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 158static void 159check_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 176static void 177check_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 222static void 223check_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 330static void 331check_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 434int 435main (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 487int 488main (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 498int 499main (void) 500{ 501 /* We have nothing to test. */ 502 return 77; 503} 504 505#endif /* HAVE_STDARG */ 506