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