(root)/
glibc-2.38/
stdlib/
gen-tst-strtod-round.c
       1  /* Generate table of tests in tst-strtod-round.c from
       2     tst-strtod-round-data.
       3     Copyright (C) 2012-2023 Free Software Foundation, Inc.
       4     This file is part of the GNU C Library.
       5  
       6     The GNU C Library is free software; you can redistribute it and/or
       7     modify it under the terms of the GNU Lesser General Public
       8     License as published by the Free Software Foundation; either
       9     version 2.1 of the License, or (at your option) any later version.
      10  
      11     The GNU C Library is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14     Lesser General Public License for more details.
      15  
      16     You should have received a copy of the GNU Lesser General Public
      17     License along with the GNU C Library; if not, see
      18     <https://www.gnu.org/licenses/>.  */
      19  
      20  /* Compile this program as:
      21  
      22     gcc -std=gnu11 -O2 -Wall -Wextra gen-tst-strtod-round.c -lmpfr \
      23       -o gen-tst-strtod-round
      24  
      25     (use of current MPFR version recommended) and run it as:
      26  
      27     gen-tst-strtod-round tst-strtod-round-data tst-strtod-round-data.h
      28  
      29     The output file will be generated as tst-strtod-round-data.h
      30  */
      31  
      32  
      33  #define _GNU_SOURCE
      34  #include <assert.h>
      35  #include <stdbool.h>
      36  #include <stdio.h>
      37  #include <stdlib.h>
      38  #include <string.h>
      39  #include <mpfr.h>
      40  
      41  /* Work around incorrect ternary value from mpfr_strtofr
      42     <https://sympa.inria.fr/sympa/arc/mpfr/2012-08/msg00005.html>.  */
      43  #define WORKAROUND
      44  
      45  static int
      46  string_to_fp (mpfr_t f, const char *s, mpfr_rnd_t rnd)
      47  {
      48    mpfr_clear_overflow ();
      49  #ifdef WORKAROUND
      50    mpfr_t f2;
      51    mpfr_init2 (f2, 100000);
      52    int r0 = mpfr_strtofr (f2, s, NULL, 0, rnd);
      53    int r = mpfr_set (f, f2, rnd);
      54    r |= mpfr_subnormalize (f, r, rnd);
      55    mpfr_clear (f2);
      56    return r0 | r;
      57  #else
      58    int r = mpfr_strtofr (f, s, NULL, 0, rnd);
      59    r |= mpfr_subnormalize (f, r, rnd);
      60    return r;
      61  #endif
      62  }
      63  
      64  void
      65  print_fp (FILE *fout, mpfr_t f, const char *suffix)
      66  {
      67    if (mpfr_inf_p (f))
      68      mpfr_fprintf (fout, "\t%sINF%s", mpfr_signbit (f) ? "-" : "", suffix);
      69    else
      70      mpfr_fprintf (fout, "\t%Ra%s", f, suffix);
      71  }
      72  
      73  static void
      74  round_str (FILE *fout, const char *s, int prec, int emin, int emax,
      75  	   bool ibm_ld)
      76  {
      77    mpfr_t max_value;
      78    mpfr_t f;
      79    mpfr_set_default_prec (prec);
      80    mpfr_set_emin (emin);
      81    mpfr_set_emax (emax);
      82    mpfr_init (f);
      83    int r = string_to_fp (f, s, MPFR_RNDD);
      84    bool overflow = mpfr_overflow_p () != 0;
      85    if (ibm_ld)
      86      {
      87        assert (prec == 106 && emin == -1073 && emax == 1024);
      88        /* The maximum value in IBM long double has discontiguous
      89  	 mantissa bits.  */
      90        mpfr_init2 (max_value, 107);
      91        mpfr_set_str (max_value, "0x1.fffffffffffff7ffffffffffffcp+1023", 0,
      92  		    MPFR_RNDN);
      93        if (mpfr_cmpabs (f, max_value) > 0)
      94  	{
      95  	  r = 1;
      96  	  overflow = true;
      97  	}
      98      }
      99    mpfr_fprintf (fout, "\t%s,\n", r ? "false" : "true");
     100    print_fp (fout, f, overflow ? ", true,\n" : ", false,\n");
     101    string_to_fp (f, s, MPFR_RNDN);
     102    overflow = (mpfr_overflow_p () != 0
     103  	      || (ibm_ld && mpfr_cmpabs (f, max_value) > 0));
     104    print_fp (fout, f, overflow ? ", true,\n" : ", false,\n");
     105    string_to_fp (f, s, MPFR_RNDZ);
     106    overflow = (mpfr_overflow_p () != 0
     107  	      || (ibm_ld && mpfr_cmpabs (f, max_value) > 0));
     108    print_fp (fout, f, overflow ? ", true,\n" : ", false,\n");
     109    string_to_fp (f, s, MPFR_RNDU);
     110    overflow = (mpfr_overflow_p () != 0
     111  	      || (ibm_ld && mpfr_cmpabs (f, max_value) > 0));
     112    print_fp (fout, f, overflow ? ", true" : ", false");
     113    mpfr_clear (f);
     114    if (ibm_ld)
     115      mpfr_clear (max_value);
     116  }
     117  
     118  static void
     119  round_for_all (FILE *fout, const char *s)
     120  {
     121    static const struct fmt {
     122      int prec;
     123      int emin;
     124      int emax;
     125      bool ibm_ld;
     126    } formats[] = {
     127      { 24, -148, 128, false },
     128      { 53, -1073, 1024, false },
     129      /* This is the Intel extended float format.  */
     130      { 64, -16444, 16384, false },
     131      /* This is the Motorola extended float format.  */
     132      { 64, -16445, 16384, false },
     133      { 106, -1073, 1024, true },
     134      { 113, -16493, 16384, false },
     135    };
     136    mpfr_fprintf (fout, "  TEST (\"");
     137    const char *p;
     138    for (p = s; *p; p++)
     139      {
     140        fputc (*p, fout);
     141        if ((p - s) % 60 == 59 && p[1])
     142  	mpfr_fprintf (fout, "\"\n\t\"");
     143      }
     144    mpfr_fprintf (fout, "\",\n");
     145    int i;
     146    int n_formats = sizeof (formats) / sizeof (formats[0]);
     147    for (i = 0; i < n_formats; i++)
     148      {
     149        round_str (fout, s, formats[i].prec, formats[i].emin,
     150  		 formats[i].emax, formats[i].ibm_ld);
     151        if (i < n_formats - 1)
     152  	mpfr_fprintf (fout, ",\n");
     153      }
     154    mpfr_fprintf (fout, "),\n");
     155  }
     156  
     157  int
     158  main (int argc, char **argv)
     159  {
     160    char *p = NULL;
     161    size_t len;
     162    ssize_t nbytes;
     163    FILE *fin, *fout;
     164    char *fin_name, *fout_name;
     165  
     166    if (argc < 3)
     167      {
     168        fprintf (stderr, "Usage: %s <input> <output>\n", basename (argv[0]));
     169        return EXIT_FAILURE;
     170      }
     171  
     172    fin_name = argv[1];
     173    fout_name = argv[2];
     174  
     175    fin = fopen (fin_name, "r");
     176    if (fin == NULL)
     177      {
     178        perror ("Could not open input for reading");
     179        return EXIT_FAILURE;
     180      }
     181  
     182    fout = fopen (fout_name, "w");
     183    if (fout == NULL)
     184      {
     185        perror ("Could not open output for writing");
     186        return EXIT_FAILURE;
     187      }
     188  
     189    fprintf (fout, "/* This file was generated by %s from %s.  */\n",
     190  	  __FILE__, fin_name);
     191    fputs ("static const struct test tests[] = {\n", fout);
     192    while ((nbytes = getline (&p, &len, fin)) != -1)
     193      {
     194        if (p[nbytes - 1] == '\n')
     195  	p[nbytes - 1] = 0;
     196        round_for_all (fout, p);
     197        free (p);
     198        p = NULL;
     199      }
     200    fputs ("};\n", fout);
     201  
     202    return EXIT_SUCCESS;
     203  }