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