(root)/
mpfr-4.2.1/
tests/
tstckintc.c
       1  /* Test file for mpfr_custom_*
       2  
       3  Copyright 2005-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  #include "mpfr-test.h"
      24  
      25  /*************************************************************************/
      26  
      27  /* Bug found on 2022-05-05 in the mpfr_custom_get_size macro.
      28     With the buggy macro, this test will fail if mpfr_prec_t > int,
      29     typically on LP64 platforms (usual 64-bit machines).
      30     This bug could occur only for precisions close to INT_MAX or higher. */
      31  static void
      32  test_get_size (void)
      33  {
      34    unsigned int u = UINT_MAX;
      35    int i = INT_MAX;
      36  
      37    if (u <= MPFR_PREC_MAX)
      38      {
      39        mpfr_prec_t p = u;
      40        size_t s1, s2;
      41  
      42        s1 = mpfr_custom_get_size (p);
      43        s2 = mpfr_custom_get_size (u);
      44        if (s1 != s2)
      45          {
      46            printf ("Error 1 in test_get_size (mpfr_custom_get_size macro).\n");
      47            printf ("Expected %lu\n", (unsigned long) s1);
      48            printf ("Got      %lu\n", (unsigned long) s2);
      49            exit (1);
      50          }
      51      }
      52  
      53    if (i <= MPFR_PREC_MAX)
      54      {
      55        mpfr_prec_t p = i;
      56        size_t s1, s2;
      57  
      58        s1 = mpfr_custom_get_size (p);
      59        s2 = mpfr_custom_get_size (i);
      60        if (s1 != s2)
      61          {
      62            printf ("Error 2 in test_get_size (mpfr_custom_get_size macro).\n");
      63            printf ("Expected %lu\n", (unsigned long) s1);
      64            printf ("Got      %lu\n", (unsigned long) s2);
      65            exit (1);
      66          }
      67      }
      68  }
      69  
      70  /*************************************************************************/
      71  
      72  #define BUFFER_SIZE 250
      73  #define PREC_TESTED 200
      74  
      75  long Buffer[BUFFER_SIZE];
      76  char *stack = (char *) Buffer;
      77  long *org = (long *) Buffer;
      78  mpfr_prec_t p = PREC_TESTED;
      79  
      80  #define ALIGNED(s) (((s) + sizeof (long) - 1) / sizeof (long) * sizeof (long))
      81  
      82  /* This code ensures alignment to "long". However, this might not be
      83     sufficient on some platforms. GCC's -Wcast-align=strict option can
      84     be useful, but this needs successive casts to help GCC, e.g.
      85  
      86     newx = (mpfr_ptr) (long *) (void *) old_stack;
      87  
      88     successively casts old_stack (of type char *) to
      89     - void *: avoid a false positive for the following cast to long *
      90       (as the code takes care of alignment to "long");
      91     - long *: this corresponds to the alignment checked by MPFR; coming
      92       from void *, it will not trigger a warning (even if incorrect);
      93     - mpfr_ptr: -Wcast-align=strict will emit a warning if mpfr_ptr has
      94       an alignment requirement stronger than long *. In such a case,
      95       the code will have to be fixed.
      96  */
      97  
      98  static void *
      99  new_st (size_t s)
     100  {
     101    void *p = (void *) stack;
     102  
     103    if (MPFR_UNLIKELY (s > (char *) &Buffer[BUFFER_SIZE] - stack))
     104      {
     105        printf ("[INTERNAL TEST ERROR] Stack overflow.\n");
     106        exit (1);
     107      }
     108    stack += ALIGNED (s);
     109    return p;
     110  }
     111  
     112  static void
     113  reset_stack (void)
     114  {
     115    stack = (char *) Buffer;
     116  }
     117  
     118  /*************************************************************************/
     119  
     120  /* Alloc a new mpfr_t on the main stack */
     121  static mpfr_ptr
     122  new_mpfr (mpfr_prec_t p)
     123  {
     124    mpfr_ptr x = (mpfr_ptr) new_st (sizeof (mpfr_t));
     125    void *mantissa = new_st (mpfr_custom_get_size (p));
     126  
     127    mpfr_custom_init (mantissa, p);
     128    mpfr_custom_init_set (x, 0, 0, p, mantissa);
     129    return x;
     130  }
     131  
     132  /* Alloc a new mpfr_t on the main stack */
     133  static mpfr_ptr
     134  new_nan1 (mpfr_prec_t p)
     135  {
     136    mpfr_ptr x = (mpfr_ptr) new_st (sizeof (mpfr_t));
     137    void *mantissa = new_st ((mpfr_custom_get_size) (p));
     138  
     139    (mpfr_custom_init) (mantissa, p);
     140    (mpfr_custom_init_set) (x, MPFR_NAN_KIND, 0, p, mantissa);
     141    return x;
     142  }
     143  
     144  /* Alloc a new mpfr_t on the main stack */
     145  static mpfr_ptr
     146  new_nan2 (mpfr_prec_t p)
     147  {
     148    mpfr_ptr x = (mpfr_ptr) new_st (sizeof (mpfr_t));
     149    void *mantissa = new_st ((mpfr_custom_get_size) (p));
     150    int i1, i2, i3, i4, i5;
     151  
     152    /* Check side effects. */
     153    i1 = i2 = 0;
     154    mpfr_custom_init ((i1++, mantissa), (i2++, p));
     155    MPFR_ASSERTN (i1 == 1);
     156    MPFR_ASSERTN (i2 == 1);
     157  
     158    /* Check that the type "void *" can be used in C, like with the function
     159       (forbidden in C++). Also check side effects. */
     160    i1 = i2 = i3 = i4 = i5 = 0;
     161  #ifdef IGNORE_CPP_COMPAT
     162  #pragma GCC diagnostic push
     163  #pragma GCC diagnostic ignored "-Wc++-compat"
     164  #endif
     165    mpfr_custom_init_set ((i1++, VOIDP_CAST(x)),
     166                          (i2++, MPFR_NAN_KIND),
     167                          (i3++, 0),
     168                          (i4++, p),
     169                          (i5++, mantissa));
     170  #ifdef IGNORE_CPP_COMPAT
     171  #pragma GCC diagnostic pop
     172  #endif
     173    MPFR_ASSERTN (i1 == 1);
     174    MPFR_ASSERTN (i2 == 1);
     175    MPFR_ASSERTN (i3 == 1);
     176    MPFR_ASSERTN (i4 == 1);
     177    MPFR_ASSERTN (i5 == 1);
     178  
     179    return x;
     180  }
     181  
     182  /* Alloc a new mpfr_t on the main stack */
     183  static mpfr_ptr
     184  new_inf (mpfr_prec_t p)
     185  {
     186    mpfr_ptr x = (mpfr_ptr) new_st (sizeof (mpfr_t));
     187    void *mantissa = new_st ((mpfr_custom_get_size) (p));
     188  
     189    (mpfr_custom_init) (mantissa, p);
     190    (mpfr_custom_init_set) (x, -MPFR_INF_KIND, 0, p, mantissa);
     191    return x;
     192  }
     193  
     194  /* Garbage the stack by keeping only x and save it in old_stack */
     195  static mpfr_ptr
     196  return_mpfr (mpfr_ptr x, char *old_stack)
     197  {
     198    void *mantissa       = mpfr_custom_get_significand (x);
     199    size_t size_mantissa = mpfr_custom_get_size (mpfr_get_prec (x));
     200    mpfr_ptr newx;
     201    long *newx2;
     202    int i1, i2;
     203  
     204    /* Check that the type "void *" can be used in C, like with the function
     205       (forbidden in C++). Also check side effects. */
     206    i1 = 0;
     207  #ifdef IGNORE_CPP_COMPAT
     208  #pragma GCC diagnostic push
     209  #pragma GCC diagnostic ignored "-Wc++-compat"
     210  #endif
     211    MPFR_ASSERTN (mpfr_custom_get_significand ((i1++, VOIDP_CAST(x)))
     212                  == mantissa);
     213  #ifdef IGNORE_CPP_COMPAT
     214  #pragma GCC diagnostic pop
     215  #endif
     216    MPFR_ASSERTN (i1 == 1);
     217  
     218    memmove (old_stack, x, sizeof (mpfr_t));
     219    memmove (old_stack + ALIGNED (sizeof (mpfr_t)), mantissa, size_mantissa);
     220    newx = (mpfr_ptr) (long *) (void *) old_stack;
     221    newx2 = (long *) (void *) (old_stack + ALIGNED (sizeof (mpfr_t)));
     222  
     223    /* Check that the type "void *" can be used in C, like with the function
     224       (forbidden in C++). Also check side effects. */
     225    i1 = i2 = 0;
     226  #ifdef IGNORE_CPP_COMPAT
     227  #pragma GCC diagnostic push
     228  #pragma GCC diagnostic ignored "-Wc++-compat"
     229  #endif
     230    mpfr_custom_move ((i1++, VOIDP_CAST(newx)), (i2++, newx2));
     231  #ifdef IGNORE_CPP_COMPAT
     232  #pragma GCC diagnostic pop
     233  #endif
     234    MPFR_ASSERTN (i1 == 1);
     235    MPFR_ASSERTN (i2 == 1);
     236  
     237    stack = (char *) newx2 + ALIGNED (size_mantissa);
     238    return newx;
     239  }
     240  
     241  /* Garbage the stack by keeping only x and save it in old_stack */
     242  static mpfr_ptr
     243  return_mpfr_func (mpfr_ptr x, char *old_stack)
     244  {
     245    void *mantissa       = (mpfr_custom_get_significand) (x);
     246    size_t size_mantissa = (mpfr_custom_get_size) (mpfr_get_prec (x));
     247    mpfr_ptr newx;
     248  
     249    memmove (old_stack, x, sizeof (mpfr_t));
     250    memmove (old_stack + ALIGNED (sizeof (mpfr_t)), mantissa, size_mantissa);
     251    newx = (mpfr_ptr) (long *) (void *) old_stack;
     252    (mpfr_custom_move) (newx, old_stack + ALIGNED (sizeof (mpfr_t)));
     253    stack = old_stack + ALIGNED (sizeof (mpfr_t)) + ALIGNED (size_mantissa);
     254    return newx;
     255  }
     256  
     257  /*************************************************************************/
     258  
     259  static void
     260  test1 (void)
     261  {
     262    mpfr_ptr x, y;
     263  
     264    reset_stack ();
     265    org = (long *) (void *) stack;
     266  
     267    x = new_mpfr (p);
     268    y = new_mpfr (p);
     269    mpfr_set_ui (x, 42, MPFR_RNDN);
     270    mpfr_set_ui (y, 17, MPFR_RNDN);
     271    mpfr_add (y, x, y, MPFR_RNDN);
     272    y = return_mpfr (y, (char *) org);
     273    if ((long *) y != org || mpfr_cmp_ui (y, 59) != 0)
     274      {
     275        printf ("Compact (1) failed!\n");
     276        exit (1);
     277      }
     278  
     279    x = new_mpfr (p);
     280    y = new_mpfr (p);
     281    mpfr_set_ui (x, 4217, MPFR_RNDN);
     282    mpfr_set_ui (y, 1742, MPFR_RNDN);
     283    mpfr_add (y, x, y, MPFR_RNDN);
     284    y = return_mpfr_func (y, (char *) org);
     285    if ((long *) y != org || mpfr_cmp_ui (y, 5959) != 0)
     286      {
     287        printf ("Compact (5) failed!\n");
     288        exit (1);
     289      }
     290  
     291    reset_stack ();
     292  }
     293  
     294  static void
     295  test_nan_inf_zero (void)
     296  {
     297    mpfr_ptr val;
     298    mpfr_srcptr sval;  /* for compilation error checking */
     299    int sign;
     300    int kind;
     301  
     302    reset_stack ();
     303  
     304    val = new_mpfr (MPFR_PREC_MIN);
     305    sval = val;
     306    mpfr_set_nan (val);
     307    kind = (mpfr_custom_get_kind) (sval);
     308    if (kind != MPFR_NAN_KIND)
     309      {
     310        printf ("mpfr_custom_get_kind error: ");
     311        mpfr_dump (val);
     312        printf (" is kind %d instead of %d\n", kind, (int) MPFR_NAN_KIND);
     313        exit (1);
     314      }
     315  
     316    val = new_nan1 (MPFR_PREC_MIN);
     317    if (!mpfr_nan_p(val))
     318      {
     319        printf ("Error: mpfr_custom_init_set doesn't set NAN mpfr (1).\n");
     320        exit (1);
     321      }
     322  
     323    val = new_nan2 (MPFR_PREC_MIN);
     324    if (!mpfr_nan_p(val))
     325      {
     326        printf ("Error: mpfr_custom_init_set doesn't set NAN mpfr (2).\n");
     327        exit (1);
     328      }
     329  
     330    val = new_inf (MPFR_PREC_MIN);
     331    if (!mpfr_inf_p(val) || mpfr_sgn(val) >= 0)
     332      {
     333        printf ("Error: mpfr_custom_init_set doesn't set -INF mpfr.\n");
     334        exit (1);
     335      }
     336  
     337    sign = 1;
     338    mpfr_set_inf (val, sign);
     339    kind = (mpfr_custom_get_kind) (val);
     340    if ((ABS (kind) != MPFR_INF_KIND) || (VSIGN (kind) != VSIGN (sign)))
     341      {
     342        printf ("mpfr_custom_get_kind error: ");
     343        mpfr_dump (val);
     344        printf (" is kind %d instead of %d\n", kind, (int) MPFR_INF_KIND);
     345        printf (" have sign %d instead of %d\n", VSIGN (kind), VSIGN (sign));
     346        exit (1);
     347      }
     348  
     349    sign = -1;
     350    mpfr_set_zero (val, sign);
     351    kind = (mpfr_custom_get_kind) (val);
     352    if ((ABS (kind) != MPFR_ZERO_KIND) || (VSIGN (kind) != VSIGN (sign)))
     353      {
     354        printf ("mpfr_custom_get_kind error: ");
     355        mpfr_dump (val);
     356        printf (" is kind %d instead of %d\n", kind, (int) MPFR_ZERO_KIND);
     357        printf (" have sign %d instead of %d\n", VSIGN (kind), VSIGN (sign));
     358        exit (1);
     359      }
     360  
     361    reset_stack ();
     362  }
     363  
     364  /*************************************************************************/
     365  
     366  /* We build the MPFR variable each time it is needed */
     367  /* a[0] is the kind, a[1] is the exponent, &a[2] is the mantissa */
     368  static long *
     369  dummy_new (void)
     370  {
     371    long *r;
     372  
     373    r = (long *) new_st (ALIGNED (2 * sizeof (long)) +
     374                         ALIGNED (mpfr_custom_get_size (p)));
     375    (mpfr_custom_init) (&r[2], p);
     376    r[0] = (int) MPFR_NAN_KIND;
     377    r[1] = 0;
     378    return r;
     379  }
     380  
     381  static long *
     382  dummy_set_si (long si)
     383  {
     384    mpfr_t x;
     385    mpfr_srcptr px;  /* for compilation error checking */
     386    long *r = dummy_new ();
     387    int i1, i2, i3, i4, i5;
     388  
     389    /* Check that the type "void *" can be used, like with the function.
     390       Also check side effects. */
     391    i1 = i2 = i3 = i4 = i5 = 0;
     392  #ifdef IGNORE_CPP_COMPAT
     393  #pragma GCC diagnostic push
     394  #pragma GCC diagnostic ignored "-Wc++-compat"
     395  #endif
     396    mpfr_custom_init_set ((i1++, VOIDP_CAST(x)),
     397                          (i2++, MPFR_REGULAR_KIND),
     398                          (i3++, 0),
     399                          (i4++, p),
     400                          (i5++, &r[2]));
     401  #ifdef IGNORE_CPP_COMPAT
     402  #pragma GCC diagnostic pop
     403  #endif
     404    MPFR_ASSERTN (i1 == 1);
     405    MPFR_ASSERTN (i2 == 1);
     406    MPFR_ASSERTN (i3 == 1);
     407    MPFR_ASSERTN (i4 == 1);
     408    MPFR_ASSERTN (i5 == 1);
     409  
     410    mpfr_set_si (x, si, MPFR_RNDN);
     411    px = x;
     412    r[0] = mpfr_custom_get_kind (px);
     413  
     414    /* Check that the type "void *" can be used in C, like with the function
     415       (forbidden in C++). Also check side effects. */
     416    i1 = 0;
     417  #ifdef IGNORE_CPP_COMPAT
     418  #pragma GCC diagnostic push
     419  #pragma GCC diagnostic ignored "-Wc++-compat"
     420  #endif
     421    MPFR_ASSERTN (mpfr_custom_get_kind ((i1++, VOIDP_CAST(x))) == r[0]);
     422  #ifdef IGNORE_CPP_COMPAT
     423  #pragma GCC diagnostic pop
     424  #endif
     425    MPFR_ASSERTN (i1 == 1);
     426  
     427    r[1] = mpfr_custom_get_exp (x);
     428  
     429    /* Check that the type "void *" can be used in C, like with the function
     430       (forbidden in C++). Also check side effects. */
     431    i1 = 0;
     432  #ifdef IGNORE_CPP_COMPAT
     433  #pragma GCC diagnostic push
     434  #pragma GCC diagnostic ignored "-Wc++-compat"
     435  #endif
     436    MPFR_ASSERTN (mpfr_custom_get_exp ((i1++, VOIDP_CAST(x))) == r[1]);
     437  #ifdef IGNORE_CPP_COMPAT
     438  #pragma GCC diagnostic pop
     439  #endif
     440    MPFR_ASSERTN (i1 == 1);
     441  
     442    return r;
     443  }
     444  
     445  static long *
     446  dummy_add (long *a, long *b)
     447  {
     448    mpfr_t x, y, z;
     449    long *r = dummy_new ();
     450  
     451    mpfr_custom_init_set (x, 0 + MPFR_REGULAR_KIND, 0, p, &r[2]);
     452    (mpfr_custom_init_set) (y, a[0], a[1], p, &a[2]);
     453    mpfr_custom_init_set (z, 0 + b[0], b[1], p, &b[2]);
     454    mpfr_add (x, y, z, MPFR_RNDN);
     455    r[0] = (mpfr_custom_get_kind) (x);
     456    r[1] = (mpfr_custom_get_exp) (x);
     457    return r;
     458  }
     459  
     460  static long *
     461  dummy_compact (long *r, long *org_stack)
     462  {
     463    memmove (org_stack, r,
     464             ALIGNED (2*sizeof (long)) + ALIGNED ((mpfr_custom_get_size) (p)));
     465    return org_stack;
     466  }
     467  
     468  /*************************************************************************/
     469  
     470  static void
     471  test2 (void)
     472  {
     473    mpfr_t x;
     474    long *a, *b, *c;
     475  
     476    reset_stack ();
     477    org = (long *) (void *) stack;
     478  
     479    a = dummy_set_si (42);
     480    b = dummy_set_si (17);
     481    c = dummy_add (a, b);
     482    c = dummy_compact (c, org);
     483    (mpfr_custom_init_set) (x, c[0], c[1], p, &c[2]);
     484    if (c != org || mpfr_cmp_ui (x, 59) != 0)
     485      {
     486        printf ("Compact (2) failed! c=%p a=%p\n", (void *) c, (void *) a);
     487        mpfr_dump (x);
     488        exit (1);
     489      }
     490  
     491    a = dummy_set_si (42);
     492    b = dummy_set_si (-17);
     493    c = dummy_add (a, b);
     494    c = dummy_compact (c, org);
     495    (mpfr_custom_init_set) (x, c[0], c[1], p, &c[2]);
     496    if (c != org || mpfr_cmp_ui (x, 25) != 0)
     497      {
     498        printf ("Compact (6) failed! c=%p a=%p\n", (void *) c, (void *) a);
     499        mpfr_dump (x);
     500        exit (1);
     501      }
     502  
     503    reset_stack ();
     504  }
     505  
     506  
     507  int
     508  main (void)
     509  {
     510    tests_start_mpfr ();
     511    test_get_size ();
     512    /* We test iff long = mp_limb_t */
     513    if (sizeof (long) == sizeof (mp_limb_t))
     514      {
     515        test1 ();
     516        test2 ();
     517        test_nan_inf_zero ();
     518      }
     519    tests_end_mpfr ();
     520    return 0;
     521  }