1/* tfprintf.c -- test file for mpfr_fprintf and mpfr_vfprintf 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#ifdef HAVE_STDARG 24#include <stdarg.h> 25 26#include <stdio.h> 27#include <stdlib.h> 28#include <float.h> 29#include <stddef.h> 30 31#include "mpfr-intmax.h" 32#include "mpfr-test.h" 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#define check_length(num_test, var, value, var_spec) \ 40 if ((var) != (value)) \ 41 { \ 42 printf ("Error in test #%d: mpfr_vfprintf printed %"QUOTE(var_spec) \ 43 " characters instead of %d\n", (num_test), (var), (value)); \ 44 exit (1); \ 45 } 46 47#define check_length_with_cmp(num_test, var, value, cmp, var_spec) \ 48 if (cmp != 0) \ 49 { \ 50 mpfr_printf ("Error in test #%d, mpfr_vfprintf printed %" \ 51 QUOTE(var_spec)" characters instead of %d\n", \ 52 (num_test), (var), (value)); \ 53 exit (1); \ 54 } 55 56/* limit for random precision in random() */ 57const int prec_max_printf = 5000; 58 59static void 60check (FILE *fout, const char *fmt, mpfr_t x) 61{ 62 if (mpfr_fprintf (fout, fmt, x) == -1) 63 { 64 mpfr_printf ("Error in mpfr_fprintf(fout, \"%s\", %Re)\n", 65 fmt, x); 66 exit (1); 67 } 68 fputc ('\n', fout); 69} 70 71static void 72check_vfprintf (FILE *fout, const char *fmt, ...) 73{ 74 va_list ap; 75 76 va_start (ap, fmt); 77 if (mpfr_vfprintf (fout, fmt, ap) == -1) 78 { 79 mpfr_printf ("Error in mpfr_vfprintf(fout, \"%s\", ...)\n", fmt); 80 81 va_end (ap); 82 exit (1); 83 } 84 85 va_end (ap); 86 fputc ('\n', fout); 87} 88 89static void 90check_special (FILE *fout) 91{ 92 mpfr_t x; 93 94 mpfr_init (x); 95 96 mpfr_set_inf (x, 1); 97 check (fout, "%Ra", x); 98 check (fout, "%Rb", x); 99 check (fout, "%Re", x); 100 check (fout, "%Rf", x); 101 check (fout, "%Rg", x); 102 check_vfprintf (fout, "%Ra", x); 103 check_vfprintf (fout, "%Rb", x); 104 check_vfprintf (fout, "%Re", x); 105 check_vfprintf (fout, "%Rf", x); 106 check_vfprintf (fout, "%Rg", x); 107 108 mpfr_set_inf (x, -1); 109 check (fout, "%Ra", x); 110 check (fout, "%Rb", x); 111 check (fout, "%Re", x); 112 check (fout, "%Rf", x); 113 check (fout, "%Rg", x); 114 check_vfprintf (fout, "%Ra", x); 115 check_vfprintf (fout, "%Rb", x); 116 check_vfprintf (fout, "%Re", x); 117 check_vfprintf (fout, "%Rf", x); 118 check_vfprintf (fout, "%Rg", x); 119 120 mpfr_set_nan (x); 121 check (fout, "%Ra", x); 122 check (fout, "%Rb", x); 123 check (fout, "%Re", x); 124 check (fout, "%Rf", x); 125 check (fout, "%Rg", x); 126 check_vfprintf (fout, "%Ra", x); 127 check_vfprintf (fout, "%Rb", x); 128 check_vfprintf (fout, "%Re", x); 129 check_vfprintf (fout, "%Rf", x); 130 check_vfprintf (fout, "%Rg", x); 131 132 mpfr_clear (x); 133} 134 135static void 136check_mixed (FILE *fout) 137{ 138 int ch = 'a'; 139#ifndef NPRINTF_HH 140 signed char sch = -1; 141 unsigned char uch = 1; 142#endif 143 short sh = -1; 144 unsigned short ush = 1; 145 int i = -1; 146 int j = 1; 147 unsigned int ui = 1; 148 long lo = -1; 149 unsigned long ulo = 1; 150 float f = -1.25; 151 double d = -1.25; 152#if !defined(NPRINTF_T) || !defined(NPRINTF_L) 153 long double ld = -1.25; 154#endif 155 156#ifndef NPRINTF_T 157 ptrdiff_t p = 1, saved_p; 158#endif 159 size_t sz = 1; 160 161 mpz_t mpz; 162 mpq_t mpq; 163 mpf_t mpf; 164 mpfr_rnd_t rnd = MPFR_RNDN; 165 166 mp_size_t limb_size = 3; 167 mp_limb_t limb[3]; 168 169 mpfr_t mpfr; 170 mpfr_prec_t prec = 53; 171 172 mpz_init (mpz); 173 mpz_set_ui (mpz, ulo); 174 mpq_init (mpq); 175 mpq_set_si (mpq, lo, ulo); 176 mpf_init (mpf); 177 mpf_set_q (mpf, mpq); 178 179 mpfr_init2 (mpfr, prec); 180 mpfr_set_f (mpfr, mpf, MPFR_RNDN); 181 182 limb[0] = limb[1] = limb[2] = ~ (mp_limb_t) 0; 183 184 check_vfprintf (fout, "a. %Ra, b. %u, c. %lx%n", mpfr, ui, ulo, &j); 185 check_length (1, j, 22, d); 186 check_vfprintf (fout, "a. %c, b. %Rb, c. %u, d. %li%ln", i, mpfr, i, 187 lo, &ulo); 188 check_length (2, ulo, 36, lu); 189 check_vfprintf (fout, "a. %hi, b. %*f, c. %Re%hn", ush, 3, f, mpfr, &ush); 190 check_length (3, ush, 29, hu); 191 check_vfprintf (fout, "a. %hi, b. %f, c. %#.2Rf%n", sh, d, mpfr, &i); 192 check_length (4, i, 29, d); 193 check_vfprintf (fout, "a. %R*A, b. %Fe, c. %i%zn", rnd, mpfr, mpf, sz, 194 &sz); 195 check_length (5, (unsigned long) sz, 34, lu); /* no format specifier "%zu" in C89 */ 196 check_vfprintf (fout, "a. %Pu, b. %c, c. %Zi%Zn", prec, ch, mpz, &mpz); 197 check_length_with_cmp (6, mpz, 17, mpz_cmp_ui (mpz, 17), Zi); 198 check_vfprintf (fout, "%% a. %#.0RNg, b. %Qx%Rn, c. %p", mpfr, mpq, &mpfr, 199 (void *) &i); 200 check_length_with_cmp (7, mpfr, 15, mpfr_cmp_ui (mpfr, 15), Rg); 201 202#ifndef NPRINTF_T 203 saved_p = p; 204 check_vfprintf (fout, "%% a. %RNg, b. %Qx, c. %td%tn", mpfr, mpq, p, &p); 205 if (p != 20) 206 mpfr_fprintf (stderr, "Error in test 8, got '%% a. %RNg, b. %Qx, c. %td'\n", mpfr, mpq, saved_p); 207 check_length (8, (long) p, 20, ld); /* no format specifier "%td" in C89 */ 208#endif 209 210#ifndef NPRINTF_L 211 check_vfprintf (fout, "a. %RA, b. %Lf, c. %QX%zn", mpfr, ld, mpq, &sz); 212 check_length (9, (unsigned long) sz, 30, lu); /* no format specifier "%zu" in C89 */ 213#endif 214 215#ifndef NPRINTF_HH 216 check_vfprintf (fout, "a. %hhi, b. %RA, c. %hhu%hhn", sch, mpfr, uch, &uch); 217 check_length (10, (unsigned int) uch, 22, u); /* no format specifier "%hhu" in C89 */ 218#endif 219 220#if (__GNU_MP_VERSION * 10 + __GNU_MP_VERSION_MINOR) >= 42 221 /* The 'M' specifier was added in gmp 4.2.0 */ 222 check_vfprintf (fout, "a. %Mx b. %Re%Mn", limb[0], mpfr, &limb[0]); 223 if (limb[0] != 14 + GMP_NUMB_BITS / 4 || limb[1] != ~ (mp_limb_t) 0 224 || limb[2] != ~ (mp_limb_t) 0) 225 { 226 printf ("Error in test #11: mpfr_vfprintf did not print %d characters" 227 " as expected\n", 14 + (int) GMP_NUMB_BITS / 4); 228 exit (1); 229 } 230 231 limb[0] = ~ (mp_limb_t) 0; 232 /* we tell vfprintf that limb array is 2 cells wide 233 and check it doesn't go through */ 234 check_vfprintf (fout, "a. %Re .b %Nx%Nn", mpfr, limb, limb_size, limb, 235 limb_size - 1); 236 if (limb[0] != 14 + 3 * GMP_NUMB_BITS / 4 || limb[1] != (mp_limb_t) 0 237 || limb[2] != ~ (mp_limb_t) 0) 238 { 239 printf ("Error in test #12: mpfr_vfprintf did not print %d characters" 240 " as expected\n", 14 + (int) GMP_NUMB_BITS / 4); 241 exit (1); 242 } 243#endif 244 245#if defined(HAVE_LONG_LONG) && !defined(NPRINTF_LL) 246 { 247 long long llo = -1; 248 unsigned long long ullo = 1; 249 250 check_vfprintf (fout, "a. %Re, b. %llx%Qn", mpfr, ullo, &mpq); 251 check_length_with_cmp (21, mpq, 16, mpq_cmp_ui (mpq, 16, 1), Qu); 252 check_vfprintf (fout, "a. %lli, b. %Rf%Fn", llo, mpfr, &mpf); 253 check_length_with_cmp (22, mpf, 19, mpf_cmp_ui (mpf, 19), Fg); 254 } 255#endif 256 257#if defined(_MPFR_H_HAVE_INTMAX_T) && !defined(NPRINTF_J) 258 { 259 intmax_t im = -1; 260 uintmax_t uim = 1; 261 262 check_vfprintf (fout, "a. %*RA, b. %ji%Qn", 10, mpfr, im, &mpq); 263 check_length_with_cmp (31, mpq, 20, mpq_cmp_ui (mpq, 20, 1), Qu); 264 check_vfprintf (fout, "a. %.*Re, b. %jx%Fn", 10, mpfr, uim, &mpf); 265 check_length_with_cmp (32, mpf, 25, mpf_cmp_ui (mpf, 25), Fg); 266 } 267#endif 268 269 mpfr_clear (mpfr); 270 mpf_clear (mpf); 271 mpq_clear (mpq); 272 mpz_clear (mpz); 273} 274 275static void 276check_random (FILE *fout, int nb_tests) 277{ 278 int i; 279 mpfr_t x; 280 mpfr_rnd_t rnd; 281 char flag[] = 282 { 283 '-', 284 '+', 285 ' ', 286 '#', 287 '0', /* no ambiguity: first zeros are flag zero*/ 288 '\'' 289 }; 290 char specifier[] = 291 { 292 'a', 293 'b', 294 'e', 295 'f', 296 'g' 297 }; 298 mpfr_exp_t old_emin, old_emax; 299 300 old_emin = mpfr_get_emin (); 301 old_emax = mpfr_get_emax (); 302 303 mpfr_init (x); 304 305 for (i = 0; i < nb_tests; ++i) 306 { 307 int ret; 308 int j, jmax; 309 int spec, prec; 310#define FMT_SIZE 13 311 char fmt[FMT_SIZE]; /* at most something like "%-+ #0'.*R*f" */ 312 char *ptr = fmt; 313 314 tests_default_random (x, 256, MPFR_EMIN_MIN, MPFR_EMAX_MAX); 315 rnd = RND_RAND (); 316 317 spec = (int) (randlimb () % 5); 318 jmax = (spec == 3 || spec == 4) ? 6 : 5; /* ' flag only with %f or %g */ 319 /* advantage small precision */ 320 prec = (int) (randlimb () % ((randlimb () % 2) ? 10 : prec_max_printf)); 321 if (spec == 3 322 && (mpfr_get_exp (x) > prec_max_printf 323 || mpfr_get_exp (x) < -prec_max_printf)) 324 /* change style 'f' to style 'e' when number x is large */ 325 --spec; 326 327 *ptr++ = '%'; 328 for (j = 0; j < jmax; j++) 329 { 330 if (randlimb () % 3 == 0) 331 *ptr++ = flag[j]; 332 } 333 *ptr++ = '.'; 334 *ptr++ = '*'; 335 *ptr++ = 'R'; 336 *ptr++ = '*'; 337 *ptr++ = specifier[spec]; 338 *ptr = '\0'; 339 MPFR_ASSERTD (ptr - fmt < FMT_SIZE); 340 341 mpfr_fprintf (fout, "mpfr_fprintf(fout, \"%s\", %d, %s, %Re)\n", 342 fmt, prec, mpfr_print_rnd_mode (rnd), x); 343 ret = mpfr_fprintf (fout, fmt, prec, rnd, x); 344 if (ret == -1) 345 { 346 if (spec == 3 347 && (MPFR_GET_EXP (x) > INT_MAX || MPFR_GET_EXP (x) < -INT_MAX)) 348 /* normal failure: x is too large to be output with full precision */ 349 { 350 mpfr_fprintf (fout, "too large !"); 351 } 352 else 353 { 354 mpfr_printf ("Error in mpfr_fprintf(fout, \"%s\", %d, %s, %Re)\n", 355 fmt, prec, mpfr_print_rnd_mode (rnd), x); 356 exit (1); 357 } 358 } 359 mpfr_fprintf (fout, "\n"); 360 } 361 362 mpfr_set_emin (old_emin); 363 mpfr_set_emax (old_emax); 364 365 mpfr_clear (x); 366} 367 368static void 369bug_20090316 (FILE *fout) 370{ 371 mpfr_t x; 372 373 mpfr_init2 (x, 53); 374 375 /* bug 20090316: fixed in r6112 */ 376 mpfr_set_ui_2exp (x, 0x60fa2916, -30, MPFR_RNDN); 377 check (fout, "%-#.4095RDg\n", x); 378 379 mpfr_clear (x); 380} 381 382int 383main (int argc, char *argv[]) 384{ 385 FILE *fout; 386 int N; 387 388 tests_start_mpfr (); 389 390 /* with no argument: prints to /dev/null, 391 tfprintf N: prints N tests to stdout */ 392 if (argc == 1) 393 { 394 N = 1000; 395 fout = fopen ("/dev/null", "w"); 396 /* If we failed to open this device, try with a dummy file */ 397 if (fout == NULL) 398 { 399 fout = fopen ("mpfrtest.txt", "w"); 400 401 if (fout == NULL) 402 { 403 printf ("Can't open /dev/null or a temporary file\n"); 404 exit (1); 405 } 406 } 407 } 408 else 409 { 410 fout = stdout; 411 N = atoi (argv[1]); 412 } 413 414 check_special (fout); 415 check_mixed (fout); 416 check_random (fout, N); 417 418 bug_20090316 (fout); 419 420 fclose (fout); 421 tests_end_mpfr (); 422 return 0; 423} 424 425#else /* MPFR_VERSION */ 426 427int 428main (void) 429{ 430 printf ("Warning! Test disabled for this MPFR version.\n"); 431 return 0; 432} 433 434#endif /* MPFR_VERSION */ 435 436#else /* HAVE_STDARG */ 437 438int 439main (void) 440{ 441 /* We have nothing to test. */ 442 return 77; 443} 444 445#endif /* HAVE_STDARG */ 446