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