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