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