| /* Generate table of tests in tst-strtod-round.c from |
| tst-strtod-round-data. |
| Copyright (C) 2012-2018 Free Software Foundation, Inc. |
| This file is part of the GNU C Library. |
| |
| The GNU C Library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2.1 of the License, or (at your option) any later version. |
| |
| The GNU C Library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with the GNU C Library; if not, see |
| <http://www.gnu.org/licenses/>. */ |
| |
| /* Compile this program as: |
| |
| gcc -std=gnu11 -O2 -Wall -Wextra gen-tst-strtod-round.c -lmpfr \ |
| -o gen-tst-strtod-round |
| |
| (use of current MPFR version recommended) and run it as: |
| |
| gen-tst-strtod-round tst-strtod-round-data tst-strtod-round-data.h |
| |
| The output file will be generated as tst-strtod-round-data.h |
| */ |
| |
| |
| #define _GNU_SOURCE |
| #include <assert.h> |
| #include <stdbool.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <mpfr.h> |
| |
| /* Work around incorrect ternary value from mpfr_strtofr |
| <https://sympa.inria.fr/sympa/arc/mpfr/2012-08/msg00005.html>. */ |
| #define WORKAROUND |
| |
| static int |
| string_to_fp (mpfr_t f, const char *s, mpfr_rnd_t rnd) |
| { |
| #ifdef WORKAROUND |
| mpfr_t f2; |
| mpfr_init2 (f2, 100000); |
| int r0 = mpfr_strtofr (f2, s, NULL, 0, rnd); |
| int r = mpfr_set (f, f2, rnd); |
| r |= mpfr_subnormalize (f, r, rnd); |
| mpfr_clear (f2); |
| return r0 | r; |
| #else |
| int r = mpfr_strtofr (f, s, NULL, 0, rnd); |
| r |= mpfr_subnormalize (f, r, rnd); |
| return r; |
| #endif |
| } |
| |
| void |
| print_fp (FILE *fout, mpfr_t f, const char *suffix) |
| { |
| if (mpfr_inf_p (f)) |
| mpfr_fprintf (fout, "\t%sINF%s", mpfr_signbit (f) ? "-" : "", suffix); |
| else |
| mpfr_fprintf (fout, "\t%Ra%s", f, suffix); |
| } |
| |
| static void |
| round_str (FILE *fout, const char *s, int prec, int emin, int emax, |
| bool ibm_ld) |
| { |
| mpfr_t f; |
| mpfr_set_default_prec (prec); |
| mpfr_set_emin (emin); |
| mpfr_set_emax (emax); |
| mpfr_init (f); |
| int r = string_to_fp (f, s, MPFR_RNDD); |
| if (ibm_ld) |
| { |
| assert (prec == 106 && emin == -1073 && emax == 1024); |
| /* The maximum value in IBM long double has discontiguous |
| mantissa bits. */ |
| mpfr_t max_value; |
| mpfr_init2 (max_value, 107); |
| mpfr_set_str (max_value, "0x1.fffffffffffff7ffffffffffffcp+1023", 0, |
| MPFR_RNDN); |
| if (mpfr_cmpabs (f, max_value) > 0) |
| r = 1; |
| mpfr_clear (max_value); |
| } |
| mpfr_fprintf (fout, "\t%s,\n", r ? "false" : "true"); |
| print_fp (fout, f, ",\n"); |
| string_to_fp (f, s, MPFR_RNDN); |
| print_fp (fout, f, ",\n"); |
| string_to_fp (f, s, MPFR_RNDZ); |
| print_fp (fout, f, ",\n"); |
| string_to_fp (f, s, MPFR_RNDU); |
| print_fp (fout, f, ""); |
| mpfr_clear (f); |
| } |
| |
| static void |
| round_for_all (FILE *fout, const char *s) |
| { |
| static const struct fmt { |
| int prec; |
| int emin; |
| int emax; |
| bool ibm_ld; |
| } formats[] = { |
| { 24, -148, 128, false }, |
| { 53, -1073, 1024, false }, |
| /* This is the Intel extended float format. */ |
| { 64, -16444, 16384, false }, |
| /* This is the Motorola extended float format. */ |
| { 64, -16445, 16384, false }, |
| { 106, -1073, 1024, true }, |
| { 113, -16493, 16384, false }, |
| }; |
| mpfr_fprintf (fout, " TEST (\""); |
| const char *p; |
| for (p = s; *p; p++) |
| { |
| fputc (*p, fout); |
| if ((p - s) % 60 == 59 && p[1]) |
| mpfr_fprintf (fout, "\"\n\t\""); |
| } |
| mpfr_fprintf (fout, "\",\n"); |
| int i; |
| int n_formats = sizeof (formats) / sizeof (formats[0]); |
| for (i = 0; i < n_formats; i++) |
| { |
| round_str (fout, s, formats[i].prec, formats[i].emin, |
| formats[i].emax, formats[i].ibm_ld); |
| if (i < n_formats - 1) |
| mpfr_fprintf (fout, ",\n"); |
| } |
| mpfr_fprintf (fout, "),\n"); |
| } |
| |
| int |
| main (int argc, char **argv) |
| { |
| char *p = NULL; |
| size_t len; |
| ssize_t nbytes; |
| FILE *fin, *fout; |
| char *fin_name, *fout_name; |
| |
| if (argc < 3) |
| { |
| fprintf (stderr, "Usage: %s <input> <output>\n", basename (argv[0])); |
| return EXIT_FAILURE; |
| } |
| |
| fin_name = argv[1]; |
| fout_name = argv[2]; |
| |
| fin = fopen (fin_name, "r"); |
| if (fin == NULL) |
| { |
| perror ("Could not open input for reading"); |
| return EXIT_FAILURE; |
| } |
| |
| fout = fopen (fout_name, "w"); |
| if (fout == NULL) |
| { |
| perror ("Could not open output for writing"); |
| return EXIT_FAILURE; |
| } |
| |
| fprintf (fout, "/* This file was generated by %s from %s. */\n", |
| __FILE__, fin_name); |
| fputs ("static const struct test tests[] = {\n", fout); |
| while ((nbytes = getline (&p, &len, fin)) != -1) |
| { |
| if (p[nbytes - 1] == '\n') |
| p[nbytes - 1] = 0; |
| round_for_all (fout, p); |
| free (p); |
| p = NULL; |
| } |
| fputs ("};\n", fout); |
| |
| return EXIT_SUCCESS; |
| } |