Home | History | Annotate | Line # | Download | only in tests
tfprintf.c revision 1.1.1.1.8.1
      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