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