tfprintf.c revision 1.1.1.1.8.1 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