xref: /netbsd-src/external/lgpl3/mpfr/dist/tests/tfprintf.c (revision 867d70fc718005c0918b8b8b2f9d7f2d52d0a0db)
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