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