(root)/
mpfr-4.2.1/
tests/
tfpif.c
       1  /* Test file for mpfr_fpif.
       2  
       3  Copyright 2012-2023 Free Software Foundation, Inc.
       4  Contributed by Olivier Demengeon.
       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  #include <errno.h>
      24  
      25  #include "mpfr-test.h"
      26  
      27  #define FILE_NAME_RW "tfpif_rw.dat" /* temporary name (written then read) */
      28  #define FILE_NAME_R  "tfpif_r1.dat" /* fixed file name (read only) */
      29  #define FILE_NAME_R2 "tfpif_r2.dat" /* fixed file name (read only) with a
      30                                         precision > MPFR_PREC_MAX */
      31  
      32  /* Note: The perror below must be called just after the failing function,
      33     thus before fprintf (otherwise one could get an error associated with
      34     fprintf). */
      35  
      36  static void
      37  doit (int argc, char *argv[], mpfr_prec_t p1, mpfr_prec_t p2)
      38  {
      39    const char *filenameCompressed = FILE_NAME_RW;
      40    const char *data = FILE_NAME_R;
      41    int status;
      42    FILE *fh;
      43    mpfr_t x[9];
      44    mpfr_t y;
      45    int i, neg;
      46    long pos;
      47  
      48    mpfr_init2 (x[0], p1);
      49    mpfr_init2 (x[8], p1);
      50    mpfr_inits2 (p2, x[1], x[2], x[3], x[4], x[5], x[6], x[7], (mpfr_ptr) 0);
      51    mpfr_set_str1 (x[0], "45.2564215000000018562786863185465335845947265625");
      52    mpfr_set_str1 (x[1], "45.2564215000000018562786863185465335845947265625");
      53    mpfr_set_str1 (x[2], "45.2564215000000018562786863185465335845947265625");
      54    mpfr_set_exp (x[2], -48000);
      55    mpfr_set_inf (x[3], 1);
      56    mpfr_set_zero (x[4], 1);
      57    mpfr_set_nan (x[5]);
      58    mpfr_set_ui (x[6], 104348, MPFR_RNDN);
      59    mpfr_set_ui (x[7], 33215, MPFR_RNDN);
      60    mpfr_div (x[8], x[6], x[7], MPFR_RNDN);
      61    mpfr_div (x[6], x[6], x[7], MPFR_RNDN);
      62  
      63    /* we first write to file FILE_NAME_RW the numbers x[i] */
      64    fh = fopen (filenameCompressed, "w");
      65    if (fh == NULL)
      66      {
      67        perror ("doit");
      68        fprintf (stderr, "Failed to open \"%s\" for writing\n",
      69                 filenameCompressed);
      70        exit (1);
      71      }
      72  
      73    for (neg = 0; neg < 2; neg++)
      74      for (i = 0; i < 9; i++)
      75        {
      76          if (neg)
      77            MPFR_CHANGE_SIGN (x[i]);
      78  
      79          status = mpfr_fpif_export (fh, x[i]);
      80          if (status != 0)
      81            {
      82              fclose (fh);
      83              printf ("Failed to export number %d, neg=%d\n", i, neg);
      84              exit (1);
      85            }
      86  
      87          if (neg)
      88            MPFR_CHANGE_SIGN (x[i]);
      89        }
      90  
      91    if (fclose (fh) != 0)
      92      {
      93        perror ("doit");
      94        fprintf (stderr, "Failed to close \"%s\"\n", filenameCompressed);
      95        exit (1);
      96      }
      97  
      98    /* we then read back FILE_NAME_RW and check we get the same numbers x[i] */
      99    fh = fopen (filenameCompressed, "r");
     100    if (fh == NULL)
     101      {
     102        perror ("doit");
     103        fprintf (stderr, "Failed to open \"%s\" for reading\n",
     104                 filenameCompressed);
     105        exit (1);
     106      }
     107  
     108    for (neg = 0; neg < 2; neg++)
     109      for (i = 0; i < 9; i++)
     110        {
     111          mpfr_prec_t px, py;
     112  
     113          if (neg)
     114            MPFR_CHANGE_SIGN (x[i]);
     115  
     116          mpfr_init2 (y, 2);
     117          /* Set the sign bit of y to the opposite of the expected one.
     118             Thus, if mpfr_fpif_import forgets to set the sign, this will
     119             be detected. */
     120          MPFR_SET_SIGN (y, - MPFR_SIGN (x[i]));
     121          mpfr_fpif_import (y, fh);
     122          px = mpfr_get_prec (x[i]);
     123          py = mpfr_get_prec (y);
     124          if (px != py)
     125            {
     126              printf ("doit failed on written number %d, neg=%d:"
     127                      " bad precision\n", i, neg);
     128              printf ("expected %ld\n", (long) px);
     129              printf ("got      %ld\n", (long) py);
     130              exit (1);
     131            }
     132          if (MPFR_SIGN (x[i]) != MPFR_SIGN (y))
     133            {
     134              printf ("doit failed on written number %d, neg=%d:"
     135                      " bad sign\n", i, neg);
     136              printf ("expected %d\n", (int) MPFR_SIGN (x[i]));
     137              printf ("got      %d\n", (int) MPFR_SIGN (y));
     138              exit (1);
     139            }
     140          if (! SAME_VAL (x[i], y))
     141            {
     142              printf ("doit failed on written number %d, neg=%d\n", i, neg);
     143              printf ("expected "); mpfr_dump (x[i]);
     144              printf ("got      "); mpfr_dump (y);
     145              exit (1);
     146            }
     147          mpfr_clear (y);
     148  
     149          if (neg)
     150            MPFR_CHANGE_SIGN (x[i]);
     151        }
     152    fclose (fh);
     153  
     154    /* we do the same for the fixed file FILE_NAME_R, this ensures
     155       we get same results with different word size or endianness */
     156    fh = src_fopen (data, "r");
     157    if (fh == NULL)
     158      {
     159        perror ("doit");
     160        fprintf (stderr, "Failed to open \"%s\" in srcdir for reading\n", data);
     161        exit (1);
     162      }
     163  
     164    /* the fixed file FILE_NAME_R assumes p1=130 and p2=2048 */
     165    for (i = 0; i < 9 && (p1 == 130 && p2 == 2048); i++)
     166      {
     167        mpfr_prec_t px, py;
     168  
     169        mpfr_init2 (y, 2);
     170        /* Set the sign bit of y to the opposite of the expected one.
     171           Thus, if mpfr_fpif_import forgets to set the sign, this will
     172           be detected. */
     173        MPFR_SET_SIGN (y, - MPFR_SIGN (x[i]));
     174        pos = ftell (fh);
     175        mpfr_fpif_import (y, fh);
     176        px = mpfr_get_prec (x[i]);
     177        py = mpfr_get_prec (y);
     178        if (px != py)
     179          {
     180            printf ("doit failed on data number %d, neg=%d:"
     181                    " bad precision\n", i, neg);
     182            printf ("expected %ld\n", (long) px);
     183            printf ("got      %ld\n", (long) py);
     184            exit (1);
     185          }
     186        if (MPFR_SIGN (x[i]) != MPFR_SIGN (y))
     187          {
     188            printf ("doit failed on data number %d, neg=%d:"
     189                    " bad sign\n", i, neg);
     190            printf ("expected %d\n", (int) MPFR_SIGN (x[i]));
     191            printf ("got      %d\n", (int) MPFR_SIGN (y));
     192            exit (1);
     193          }
     194        if (! SAME_VAL (x[i], y))
     195          {
     196            printf ("doit failed on data number %d, neg=%d, at offset 0x%lx\n",
     197                    i, neg, (unsigned long) pos);
     198            printf ("expected "); mpfr_dump (x[i]);
     199            printf ("got      "); mpfr_dump (y);
     200            exit (1);
     201          }
     202        mpfr_clear (y);
     203      }
     204    fclose (fh);
     205  
     206    for (i = 0; i < 9; i++)
     207      mpfr_clear (x[i]);
     208  
     209    remove (filenameCompressed);
     210  }
     211  
     212  #define BAD 10
     213  
     214  static void
     215  check_bad (void)
     216  {
     217    const char *filenameCompressed = FILE_NAME_RW;
     218    int status;
     219    FILE *fh;
     220    mpfr_t x;
     221    unsigned char badData[BAD][10] =
     222      { { 7 }, { 16 }, { 23, 118 }, { 23, 95 }, { 23, 127 }, { 23, 47 },
     223        { 7, 0, 0, 0, 0, 0, 0, 0, 128, 119 }, /* +0 in a huge precision */
     224        /* precision 8-7=1, exponent on 98-94=4 bytes */
     225        { 8, 98, 255, 255, 255, 127 },
     226        /* precision 8-7=1, exponent on 102-94=8 bytes */
     227        { 8, 102, 255, 255, 255, 255, 255, 255, 255, 127 },
     228        { 8, 94 }
     229        };
     230    int badDataSize[BAD] = { 1, 1, 2, 2, 2, 2, 10, 6, 10, 2 };
     231    int i;
     232  
     233    mpfr_init2 (x, 2);
     234    status = mpfr_fpif_export (NULL, x);
     235    if (status == 0)
     236      {
     237        printf ("mpfr_fpif_export did not fail with a NULL file\n");
     238        exit (1);
     239      }
     240    status = mpfr_fpif_import (x, NULL);
     241    if (status == 0)
     242      {
     243        printf ("mpfr_fpif_import did not fail with a NULL file\n");
     244        exit (1);
     245      }
     246  
     247    /* Since the file will be read after writing to it and a rewind, we need
     248       to open it in mode "w+".
     249       Note: mode "w" was used previously, and the issue remained undetected
     250       until a test on AIX, where the fclose failed with the error:
     251         check_bad: A file descriptor does not refer to an open file.
     252       (the exit code of fclose has been checked since r13549 / 2019-08-09,
     253       at the same time "w+" was changed to "w" by mistake).
     254       What actually happened is that the fread in mpfr_fpif_import failed,
     255       but this was not tested. So a test of errno has been added below;
     256       with mode "w" (instead of "w+"), it yields:
     257         check_bad: Bad file descriptor
     258       as expected. */
     259    fh = fopen (filenameCompressed, "w+");
     260    if (fh == NULL)
     261      {
     262        perror ("check_bad");
     263        fprintf (stderr, "Failed to open \"%s\" for writing\n",
     264                filenameCompressed);
     265        remove (filenameCompressed);
     266        exit (1);
     267      }
     268    status = mpfr_fpif_import (x, fh);
     269    if (status == 0)
     270      {
     271        printf ("mpfr_fpif_import did not fail on a empty file\n");
     272        fclose (fh);
     273        remove (filenameCompressed);
     274        exit (1);
     275      }
     276  
     277    for (i = 0; i < BAD; i++)
     278      {
     279        mpfr_exp_t INITIALIZED(emax);
     280        /* The INITIALIZED() is a workaround for GCC bug 106155:
     281           https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106155 */
     282  
     283        /* For i == 6, mpfr_prec_t needs at least a 65-bit precision
     284           (64 value bits + 1 sign bit) to avoid a failure. */
     285        if (i == 6 && MPFR_PREC_BITS > 64)
     286          break;
     287        /* For i=9, we use a reduced exponent range */
     288        if (i == 9)
     289          {
     290            emax = mpfr_get_emax ();
     291            set_emax (46);
     292          }
     293        rewind (fh);
     294        status = fwrite (&badData[i][0], badDataSize[i], 1, fh);
     295        if (status != 1)
     296          {
     297            printf ("Write error on the test file\n");
     298            fclose (fh);
     299            remove (filenameCompressed);
     300            exit (1);
     301          }
     302        rewind (fh);
     303        /* The check of errno below is needed to make sure that
     304           mpfr_fpif_import fails due to bad data, not for some
     305           arbitrary system error. */
     306        errno = 0;
     307        status = mpfr_fpif_import (x, fh);
     308        if (errno != 0)
     309          {
     310            perror ("check_bad");
     311            fprintf (stderr, "mpfr_fpif_import failed with unexpected"
     312                     " errno = %d (and status = %d)\n", errno, status);
     313            fclose (fh);
     314            remove (filenameCompressed);
     315            exit (1);
     316          }
     317        if (status == 0)
     318          {
     319            printf ("mpfr_fpif_import did not fail on a bad imported data\n");
     320            switch (i)
     321              {
     322              case 0:
     323                printf ("  not enough precision data\n");
     324                break;
     325              case 1:
     326                printf ("  no exponent data\n");
     327                break;
     328              case 2:
     329                printf ("  too big exponent\n");
     330                break;
     331              case 3:
     332                printf ("  not enough exponent data\n");
     333                break;
     334              case 4:
     335                printf ("  exponent data wrong\n");
     336                break;
     337              case 5:
     338                printf ("  no limb data\n");
     339                break;
     340              case 6:
     341                printf ("  too large precision\n");
     342                break;
     343              case 7:
     344              case 8:
     345              case 9:
     346                printf ("  too large exponent\n");
     347                break;
     348              default:
     349                printf ("Test fatal error, unknown case\n");
     350                break;
     351              }
     352            fclose (fh);
     353            remove (filenameCompressed);
     354            exit (1);
     355          }
     356        if (i == 9)
     357          set_emax (emax);
     358      }
     359  
     360    if (fclose (fh) != 0)
     361      {
     362        perror ("check_bad");
     363        fprintf (stderr, "Failed to close \"%s\"\n", filenameCompressed);
     364        exit (1);
     365      }
     366  
     367    mpfr_clear (x);
     368  
     369    fh = fopen (filenameCompressed, "r");
     370    if (fh == NULL)
     371      {
     372        perror ("check_bad");
     373        fprintf (stderr, "Failed to open \"%s\" for reading\n",
     374                 filenameCompressed);
     375        exit (1);
     376      }
     377  
     378    mpfr_init2 (x, 2);
     379    status = mpfr_fpif_export (fh, x);
     380    if (status == 0)
     381      {
     382        printf ("mpfr_fpif_export did not fail on a read only stream\n");
     383        exit (1);
     384      }
     385    fclose (fh);
     386    remove (filenameCompressed);
     387    mpfr_clear (x);
     388  }
     389  
     390  /* exercise error when precision > MPFR_PREC_MAX */
     391  static void
     392  extra (void)
     393  {
     394    const char *data = FILE_NAME_R2;
     395    mpfr_t x;
     396    FILE *fp;
     397    int ret;
     398  
     399    mpfr_init2 (x, 17);
     400    mpfr_set_ui (x, 42, MPFR_RNDN);
     401    fp = src_fopen (data, "r");
     402    if (fp == NULL)
     403      {
     404        perror ("extra");
     405        fprintf (stderr, "Failed to open \"%s\" in srcdir for reading\n", data);
     406        exit (1);
     407      }
     408    ret = mpfr_fpif_import (x, fp);
     409    MPFR_ASSERTN (ret != 0);  /* import failure */
     410    MPFR_ASSERTN (mpfr_get_prec (x) == 17);  /* precision did not change */
     411    MPFR_ASSERTN (mpfr_cmp_ui0 (x, 42) == 0);  /* value is still 42 */
     412    fclose (fp);
     413    mpfr_clear (x);
     414  }
     415  
     416  int
     417  main (int argc, char *argv[])
     418  {
     419    if (argc != 1)
     420      {
     421        printf ("Usage: %s\n", argv[0]);
     422        exit (1);
     423      }
     424  
     425    tests_start_mpfr ();
     426  
     427    extra ();
     428    doit (argc, argv, 130, 2048);
     429    doit (argc, argv, 1, 53);
     430    check_bad ();
     431  
     432    tests_end_mpfr ();
     433  
     434    return 0;
     435  }