(root)/
mpfr-4.2.1/
tests/
tfprintf.c
       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
      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
      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
     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
     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
     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
     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
     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
     454  main (void)
     455  {
     456    /* We have nothing to test. */
     457    return 77;
     458  }
     459  
     460  #endif  /* HAVE_STDARG */