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