xref: /netbsd-src/external/lgpl3/mpfr/dist/tests/tprintf.c (revision 37afb7eb6895c833050f8bfb1d1bb2f99f332539)
1 /* tprintf.c -- test file for mpfr_printf and mpfr_vprintf
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 #if HAVE_STDARG
24 #include <stdarg.h>
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stddef.h>
29 
30 #include "mpfr-intmax.h"
31 #include "mpfr-test.h"
32 #define STDOUT_FILENO 1
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 /* unlike other tests, we print out errors to stderr because stdout might be
40    redirected */
41 #define check_length(num_test, var, value, var_spec)                    \
42   if ((var) != (value))                                                 \
43     {                                                                   \
44       fprintf (stderr, "Error in test #%d: mpfr_printf printed %"       \
45                QUOTE(var_spec)" characters instead of %d\n",            \
46                (num_test), (var), (value));                             \
47       exit (1);                                                         \
48     }
49 
50 #define check_length_with_cmp(num_test, var, value, cmp, var_spec)      \
51   if (cmp != 0)                                                         \
52     {                                                                   \
53       mpfr_fprintf (stderr, "Error in test #%d, mpfr_printf printed %"  \
54                     QUOTE(var_spec)" characters instead of %d\n",       \
55                     (num_test), (var), (value));                        \
56       exit (1);                                                         \
57     }
58 
59 /* limit for random precision in random() */
60 const int prec_max_printf = 5000;
61 /* boolean: is stdout redirected to a file ? */
62 int stdout_redirect;
63 
64 static void
65 check (const char *fmt, mpfr_t x)
66 {
67   if (mpfr_printf (fmt, x) == -1)
68     {
69       fprintf (stderr, "Error in mpfr_printf(\"%s\", ...)\n", fmt);
70 
71       exit (1);
72     }
73   putchar ('\n');
74 }
75 
76 static void
77 check_vprintf (const char *fmt, ...)
78 {
79   va_list ap;
80 
81   va_start (ap, fmt);
82   if (mpfr_vprintf (fmt, ap) == -1)
83     {
84       fprintf (stderr, "Error in mpfr_vprintf(\"%s\", ...)\n", fmt);
85 
86       va_end (ap);
87       exit (1);
88     }
89   putchar ('\n');
90   va_end (ap);
91 }
92 
93 static void
94 check_vprintf_failure (const char *fmt, ...)
95 {
96   va_list ap;
97 
98   va_start (ap, fmt);
99   if (mpfr_vprintf (fmt, ap) != -1)
100    {
101       putchar ('\n');
102       fprintf (stderr, "Error in mpfr_vprintf(\"%s\", ...)\n", fmt);
103 
104       va_end (ap);
105       exit (1);
106     }
107   putchar ('\n');
108   va_end (ap);
109 }
110 
111 static void
112 check_invalid_format (void)
113 {
114   int i = 0;
115 
116   /* format in disorder */
117   check_vprintf_failure ("blah %l2.1d blah", i);
118   check_vprintf_failure ("blah %2.1#d blah", i);
119 
120   /* incomplete format */
121   check_vprintf_failure ("%", i);
122   check_vprintf_failure ("% (missing conversion specifier)", i);
123   check_vprintf_failure ("missing conversion specifier %h", i);
124   check_vprintf_failure ("this should fail %.l because of missing conversion specifier "
125                          "(or doubling %%)", i);
126   check_vprintf_failure ("%L", i);
127   check_vprintf_failure ("%hh. ", i);
128   check_vprintf_failure ("blah %j.");
129   check_vprintf_failure ("%ll blah");
130   check_vprintf_failure ("blah%t blah");
131   check_vprintf_failure ("%z ");
132   check_vprintf_failure ("%F (missing conversion specifier)");
133   check_vprintf_failure ("%Q (missing conversion specifier)");
134   check_vprintf_failure ("%M (missing conversion specifier)");
135   check_vprintf_failure ("%N (missing conversion specifier)");
136   check_vprintf_failure ("%Z (missing conversion specifier)");
137   check_vprintf_failure ("%R (missing conversion specifier)");
138   check_vprintf_failure ("%R");
139   check_vprintf_failure ("%P (missing conversion specifier)");
140 
141   /* conversion specifier with wrong length specifier */
142   check_vprintf_failure ("%ha", i);
143   check_vprintf_failure ("%hhe", i);
144   check_vprintf_failure ("%jf", i);
145   check_vprintf_failure ("%lg", i);
146   check_vprintf_failure ("%tA", i);
147   check_vprintf_failure ("%zE", i);
148   check_vprintf_failure ("%Ld", i);
149   check_vprintf_failure ("%Qf", i);
150   check_vprintf_failure ("%MG", i);
151   check_vprintf_failure ("%Na", i);
152   check_vprintf_failure ("%ZE", i);
153   check_vprintf_failure ("%PG", i);
154   check_vprintf_failure ("%Fu", i);
155   check_vprintf_failure ("%Rx", i);
156 }
157 
158 static void
159 check_long_string (void)
160 {
161   /* this test is VERY expensive both in time (~1 min on core2 @ 2.40GHz) and
162      in memory (~2.5 GB) */
163   mpfr_t x;
164 
165   mpfr_init2 (x, INT_MAX);
166 
167   mpfr_set_ui (x, 1, MPFR_RNDN);
168   mpfr_nextabove (x);
169 
170   check_vprintf_failure ("%Rb", x);
171   check_vprintf_failure ("%RA %RA %Ra %Ra", x, x, x, x);
172 
173   mpfr_clear (x);
174 }
175 
176 static void
177 check_special (void)
178 {
179   mpfr_t x;
180 
181   mpfr_init (x);
182 
183   mpfr_set_inf (x, 1);
184   check ("%Ra", x);
185   check ("%Rb", x);
186   check ("%Re", x);
187   check ("%Rf", x);
188   check ("%Rg", x);
189   check_vprintf ("%Ra", x);
190   check_vprintf ("%Rb", x);
191   check_vprintf ("%Re", x);
192   check_vprintf ("%Rf", x);
193   check_vprintf ("%Rg", x);
194 
195   mpfr_set_inf (x, -1);
196   check ("%Ra", x);
197   check ("%Rb", x);
198   check ("%Re", x);
199   check ("%Rf", x);
200   check ("%Rg", x);
201   check_vprintf ("%Ra", x);
202   check_vprintf ("%Rb", x);
203   check_vprintf ("%Re", x);
204   check_vprintf ("%Rf", x);
205   check_vprintf ("%Rg", x);
206 
207   mpfr_set_nan (x);
208   check ("%Ra", x);
209   check ("%Rb", x);
210   check ("%Re", x);
211   check ("%Rf", x);
212   check ("%Rg", x);
213   check_vprintf ("%Ra", x);
214   check_vprintf ("%Rb", x);
215   check_vprintf ("%Re", x);
216   check_vprintf ("%Rf", x);
217   check_vprintf ("%Rg", x);
218 
219   mpfr_clear (x);
220 }
221 
222 static void
223 check_mixed (void)
224 {
225   int ch = 'a';
226 #ifndef NPRINTF_HH
227   signed char sch = -1;
228   unsigned char uch = 1;
229 #endif
230   short sh = -1;
231   unsigned short ush = 1;
232   int i = -1;
233   int j = 1;
234   unsigned int ui = 1;
235   long lo = -1;
236   unsigned long ulo = 1;
237   float f = -1.25;
238   double d = -1.25;
239 #if !defined(NPRINTF_T) || !defined(NPRINTF_L)
240   long double ld = -1.25;
241 #endif
242 
243 #ifndef NPRINTF_T
244   ptrdiff_t p = 1, saved_p;
245 #endif
246   size_t sz = 1;
247 
248   mpz_t mpz;
249   mpq_t mpq;
250   mpf_t mpf;
251   mpfr_rnd_t rnd = MPFR_RNDN;
252 
253   mpfr_t mpfr;
254   mpfr_prec_t prec;
255 
256   mpz_init (mpz);
257   mpz_set_ui (mpz, ulo);
258   mpq_init (mpq);
259   mpq_set_si (mpq, lo, ulo);
260   mpf_init (mpf);
261   mpf_set_q (mpf, mpq);
262   mpfr_init (mpfr);
263   mpfr_set_f (mpfr, mpf, MPFR_RNDN);
264   prec = mpfr_get_prec (mpfr);
265 
266   check_vprintf ("a. %Ra, b. %u, c. %lx%n", mpfr, ui, ulo, &j);
267   check_length (1, j, 22, d);
268   check_vprintf ("a. %c, b. %Rb, c. %u, d. %li%ln", i, mpfr, i, lo, &ulo);
269   check_length (2, ulo, 36, lu);
270   check_vprintf ("a. %hi, b. %*f, c. %Re%hn", ush, 3, f, mpfr, &ush);
271   check_length (3, ush, 29, hu);
272   check_vprintf ("a. %hi, b. %f, c. %#.2Rf%n", sh, d, mpfr, &i);
273   check_length (4, i, 29, d);
274   check_vprintf ("a. %R*A, b. %Fe, c. %i%zn", rnd, mpfr, mpf, sz, &sz);
275   check_length (5, (unsigned long) sz, 34, lu); /* no format specifier '%zu' in C89 */
276   check_vprintf ("a. %Pu, b. %c, c. %RUG, d. %Zi%Zn", prec, ch, mpfr, mpz, &mpz);
277   check_length_with_cmp (6, mpz, 24, mpz_cmp_ui (mpz, 24), Zi);
278   check_vprintf ("%% a. %#.0RNg, b. %Qx%Rn c. %p",
279                  mpfr, mpq, &mpfr, (void *) &i);
280   check_length_with_cmp (7, mpfr, 15, mpfr_cmp_ui (mpfr, 15), Rg);
281 
282 #ifndef NPRINTF_T
283   saved_p = p;
284   check_vprintf ("%% a. %RNg, b. %Qx, c. %td%tn", mpfr, mpq, p, &p);
285   if (p != 20)
286     mpfr_fprintf (stderr, "Error in test 8, got '%% a. %RNg, b. %Qx, c. %td'\n", mpfr, mpq, saved_p);
287   check_length (8, (long) p, 20, ld); /* no format specifier '%td' in C89 */
288 #endif
289 
290 #ifndef NPRINTF_L
291   check_vprintf ("a. %RA, b. %Lf, c. %QX%zn", mpfr, ld, mpq, &sz);
292   check_length (9, (unsigned long) sz, 30, lu); /* no format specifier '%zu' in C89 */
293 #endif
294 
295 #ifndef NPRINTF_HH
296   check_vprintf ("a. %hhi, b. %Ra, c. %hhu%hhn", sch, mpfr, uch, &uch);
297   check_length (10, (unsigned int) uch, 22, u); /* no format specifier '%hhu' in C89 */
298 #endif
299 
300 #if defined(HAVE_LONG_LONG) && !defined(NPRINTF_LL)
301   {
302     long long llo = -1;
303     unsigned long long ullo = 1;
304 
305     check_vprintf ("a. %Re, b. %llx%Qn", mpfr, ullo, &mpq);
306     check_length_with_cmp (11, mpq, 16, mpq_cmp_ui (mpq, 16, 1), Qu);
307     check_vprintf ("a. %lli, b. %Rf%lln", llo, mpfr, &ullo);
308     check_length (12, ullo, 19, llu);
309   }
310 #endif
311 
312 #if defined(_MPFR_H_HAVE_INTMAX_T) && !defined(NPRINTF_J)
313   {
314     intmax_t im = -1;
315     uintmax_t uim = 1;
316 
317     check_vprintf ("a. %*RA, b. %ji%Fn", 10, mpfr, im, &mpf);
318     check_length_with_cmp (31, mpf, 20, mpf_cmp_ui (mpf, 20), Fg);
319     check_vprintf ("a. %.*Re, b. %jx%jn", 10, mpfr, uim, &im);
320     check_length (32, (long) im, 25, li); /* no format specifier "%ji" in C89 */
321   }
322 #endif
323 
324   mpfr_clear (mpfr);
325   mpf_clear (mpf);
326   mpq_clear (mpq);
327   mpz_clear (mpz);
328 }
329 
330 static void
331 check_random (int nb_tests)
332 {
333   int i;
334   mpfr_t x;
335   mpfr_rnd_t rnd;
336   char flag[] =
337     {
338       '-',
339       '+',
340       ' ',
341       '#',
342       '0', /* no ambiguity: first zeros are flag zero*/
343       '\''
344     };
345   char specifier[] =
346     {
347       'a',
348       'b',
349       'e',
350       'f',
351       'g'
352     };
353   mpfr_exp_t old_emin, old_emax;
354 
355   old_emin = mpfr_get_emin ();
356   old_emax = mpfr_get_emax ();
357 
358   mpfr_init (x);
359 
360   for (i = 0; i < nb_tests; ++i)
361     {
362       int ret;
363       int j, jmax;
364       int spec, prec;
365 #define FMT_SIZE 13
366       char fmt[FMT_SIZE]; /* at most something like "%-+ #0'.*R*f" */
367       char *ptr = fmt;
368 
369       tests_default_random (x, 256, MPFR_EMIN_MIN, MPFR_EMAX_MAX);
370       rnd = (mpfr_rnd_t) RND_RAND ();
371 
372       spec = (int) (randlimb () % 5);
373       jmax = (spec == 3 || spec == 4) ? 6 : 5; /* ' flag only with %f or %g */
374       /* advantage small precision */
375       prec = (randlimb () % 2) ? 10 : prec_max_printf;
376       prec = (int) (randlimb () % prec);
377       if (spec == 3
378           && (mpfr_get_exp (x) > prec_max_printf
379               || mpfr_get_exp (x) < -prec_max_printf))
380         /*  change style 'f' to style 'e' when number x is very large or very
381             small*/
382         --spec;
383 
384       *ptr++ = '%';
385       for (j = 0; j < jmax; j++)
386         {
387           if (randlimb () % 3 == 0)
388             *ptr++ = flag[j];
389         }
390       *ptr++ = '.';
391       *ptr++ = '*';
392       *ptr++ = 'R';
393       *ptr++ = '*';
394       *ptr++ = specifier[spec];
395       *ptr = '\0';
396       MPFR_ASSERTD (ptr - fmt < FMT_SIZE);
397 
398       mpfr_printf ("mpfr_printf(\"%s\", %d, %s, %Re)\n", fmt, prec,
399                    mpfr_print_rnd_mode (rnd), x);
400       ret = mpfr_printf (fmt, prec, rnd, x);
401       if (ret == -1)
402         {
403           if (spec == 3
404               && (MPFR_GET_EXP (x) > INT_MAX || MPFR_GET_EXP (x) < -INT_MAX))
405             /* normal failure: x is too large to be output with full precision */
406             {
407               mpfr_printf ("too large !");
408             }
409           else
410             {
411               printf ("Error in mpfr_printf(\"%s\", %d, %s, ...)",
412                       fmt, prec, mpfr_print_rnd_mode (rnd));
413 
414               if (stdout_redirect)
415                 {
416                   if ((fflush (stdout) == EOF) || (fclose (stdout) == -1))
417                     {
418                       perror ("check_random");
419                       exit (1);
420                     }
421                 }
422               exit (1);
423             }
424         }
425       putchar ('\n');
426     }
427 
428   mpfr_set_emin (old_emin);
429   mpfr_set_emax (old_emax);
430 
431   mpfr_clear (x);
432 }
433 
434 int
435 main (int argc, char *argv[])
436 {
437   int N;
438 
439   tests_start_mpfr ();
440 
441   /* with no argument: prints to /dev/null,
442      tprintf N: prints N tests to stdout */
443   if (argc == 1)
444     {
445       N = 1000;
446       stdout_redirect = 1;
447       if (freopen ("/dev/null", "w", stdout) == NULL)
448         {
449           /* We failed to open this device, try with a dummy file */
450           if (freopen ("mpfrtest.txt", "w", stdout) == NULL)
451             {
452               /* Output the error message to stderr since it is not
453                  a message about a wrong result in MPFR. Anyway the
454                  stdandard output may have changed. */
455               fprintf (stderr, "Can't open /dev/null or a temporary file\n");
456               exit (1);
457             }
458         }
459     }
460   else
461     {
462       stdout_redirect = 0;
463       N = atoi (argv[1]);
464     }
465 
466   check_invalid_format ();
467   check_special ();
468   check_mixed ();
469 
470   /* expensive tests */
471   if (getenv ("MPFR_CHECK_LARGEMEM") != NULL)
472     check_long_string();
473 
474   check_random (N);
475 
476   if (stdout_redirect)
477     {
478       if ((fflush (stdout) == EOF) || (fclose (stdout) == -1))
479         perror ("main");
480     }
481   tests_end_mpfr ();
482   return 0;
483 }
484 
485 #else  /* MPFR_VERSION */
486 
487 int
488 main (void)
489 {
490   printf ("Warning! Test disabled for this MPFR version.\n");
491   return 0;
492 }
493 
494 #endif  /* MPFR_VERSION */
495 
496 #else  /* HAVE_STDARG */
497 
498 int
499 main (void)
500 {
501   /* We have nothing to test. */
502   return 77;
503 }
504 
505 #endif  /* HAVE_STDARG */
506