1 /* tfprintf.c -- test file for mpfr_fprintf and mpfr_vfprintf 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 #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() */ 57 const int prec_max_printf = 5000; 58 59 static void 60 check (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 71 static void 72 check_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 89 static void 90 check_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 135 static void 136 check_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 275 static void 276 check_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 368 static void 369 bug_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 382 int 383 main (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 427 int 428 main (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 438 int 439 main (void) 440 { 441 /* We have nothing to test. */ 442 return 77; 443 } 444 445 #endif /* HAVE_STDARG */ 446