Home | History | Annotate | Line # | Download | only in tests
      1 /* Reference floating point routines.
      2 
      3 Copyright 1996, 2001, 2004, 2005 Free Software Foundation, Inc.
      4 
      5 This file is part of the GNU MP Library test suite.
      6 
      7 The GNU MP Library test suite is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 3 of the License,
     10 or (at your option) any later version.
     11 
     12 The GNU MP Library test suite is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
     15 Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License along with
     18 the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
     19 
     20 #include <stdio.h>
     21 #include <stdlib.h>
     22 
     23 #include "gmp-impl.h"
     24 #include "tests.h"
     25 
     26 
     27 void
     28 refmpf_add (mpf_ptr w, mpf_srcptr u, mpf_srcptr v)
     29 {
     30   mp_size_t hi, lo, size;
     31   mp_ptr ut, vt, wt;
     32   int neg;
     33   mp_exp_t exp;
     34   mp_limb_t cy;
     35   TMP_DECL;
     36 
     37   TMP_MARK;
     38 
     39   if (SIZ (u) == 0)
     40     {
     41       size = ABSIZ (v);
     42       wt = TMP_ALLOC_LIMBS (size + 1);
     43       MPN_COPY (wt, PTR (v), size);
     44       exp = EXP (v);
     45       neg = SIZ (v) < 0;
     46       goto done;
     47     }
     48   if (SIZ (v) == 0)
     49     {
     50       size = ABSIZ (u);
     51       wt = TMP_ALLOC_LIMBS (size + 1);
     52       MPN_COPY (wt, PTR (u), size);
     53       exp = EXP (u);
     54       neg = SIZ (u) < 0;
     55       goto done;
     56     }
     57   if ((SIZ (u) ^ SIZ (v)) < 0)
     58     {
     59       mpf_t tmp;
     60       SIZ (tmp) = -SIZ (v);
     61       EXP (tmp) = EXP (v);
     62       PTR (tmp) = PTR (v);
     63       refmpf_sub (w, u, tmp);
     64       return;
     65     }
     66   neg = SIZ (u) < 0;
     67 
     68   /* Compute the significance of the hi and lo end of the result.  */
     69   hi = MAX (EXP (u), EXP (v));
     70   lo = MIN (EXP (u) - ABSIZ (u), EXP (v) - ABSIZ (v));
     71   size = hi - lo;
     72   ut = TMP_ALLOC_LIMBS (size + 1);
     73   vt = TMP_ALLOC_LIMBS (size + 1);
     74   wt = TMP_ALLOC_LIMBS (size + 1);
     75   MPN_ZERO (ut, size);
     76   MPN_ZERO (vt, size);
     77   {int off;
     78   off = size + (EXP (u) - hi) - ABSIZ (u);
     79   MPN_COPY (ut + off, PTR (u), ABSIZ (u));
     80   off = size + (EXP (v) - hi) - ABSIZ (v);
     81   MPN_COPY (vt + off, PTR (v), ABSIZ (v));
     82   }
     83 
     84   cy = mpn_add_n (wt, ut, vt, size);
     85   wt[size] = cy;
     86   size += cy;
     87   exp = hi + cy;
     88 
     89 done:
     90   if (size > PREC (w))
     91     {
     92       wt += size - PREC (w);
     93       size = PREC (w);
     94     }
     95   MPN_COPY (PTR (w), wt, size);
     96   SIZ (w) = neg == 0 ? size : -size;
     97   EXP (w) = exp;
     98   TMP_FREE;
     99 }
    100 
    101 
    102 /* Add 1 "unit in last place" (ie. in the least significant limb) to f.
    103    f cannot be zero, since that has no well-defined "last place".
    104 
    105    This routine is designed for use in cases where we pay close attention to
    106    the size of the data value and are using that (and the exponent) to
    107    indicate the accurate part of a result, or similar.  For this reason, if
    108    there's a carry out we don't store 1 and adjust the exponent, we just
    109    leave 100..00.  We don't even adjust if there's a carry out of prec+1
    110    limbs, but instead give up in that case (which we intend shouldn't arise
    111    in normal circumstances).  */
    112 
    113 void
    114 refmpf_add_ulp (mpf_ptr f)
    115 {
    116   mp_ptr     fp = PTR(f);
    117   mp_size_t  fsize = SIZ(f);
    118   mp_size_t  abs_fsize = ABSIZ(f);
    119   mp_limb_t  c;
    120 
    121   if (fsize == 0)
    122     {
    123       printf ("Oops, refmpf_add_ulp called with f==0\n");
    124       abort ();
    125     }
    126 
    127   c = refmpn_add_1 (fp, fp, abs_fsize, CNST_LIMB(1));
    128   if (c != 0)
    129     {
    130       if (abs_fsize >= PREC(f) + 1)
    131         {
    132           printf ("Oops, refmpf_add_ulp carried out of prec+1 limbs\n");
    133           abort ();
    134         }
    135 
    136       fp[abs_fsize] = c;
    137       abs_fsize++;
    138       SIZ(f) = (fsize > 0 ? abs_fsize : - abs_fsize);
    139       EXP(f)++;
    140     }
    141 }
    142 
    143 /* Fill f with size limbs of the given value, setup as an integer. */
    144 void
    145 refmpf_fill (mpf_ptr f, mp_size_t size, mp_limb_t value)
    146 {
    147   ASSERT (size >= 0);
    148   size = MIN (PREC(f) + 1, size);
    149   SIZ(f) = size;
    150   EXP(f) = size;
    151   refmpn_fill (PTR(f), size, value);
    152 }
    153 
    154 /* Strip high zero limbs from the f data, adjusting exponent accordingly. */
    155 void
    156 refmpf_normalize (mpf_ptr f)
    157 {
    158   while (SIZ(f) != 0 && PTR(f)[ABSIZ(f)-1] == 0)
    159     {
    160       SIZ(f) = (SIZ(f) >= 0 ? SIZ(f)-1 : SIZ(f)+1);
    161       EXP(f) --;
    162     }
    163   if (SIZ(f) == 0)
    164     EXP(f) = 0;
    165 }
    166 
    167 /* refmpf_set_overlap sets up dst as a copy of src, but with PREC(dst)
    168    unchanged, in preparation for an overlap test.
    169 
    170    The full value of src is copied, and the space at PTR(dst) is extended as
    171    necessary.  The way PREC(dst) is unchanged is as per an mpf_set_prec_raw.
    172    The return value is the new PTR(dst) space precision, in bits, ready for
    173    a restoring mpf_set_prec_raw before mpf_clear.  */
    174 
    175 unsigned long
    176 refmpf_set_overlap (mpf_ptr dst, mpf_srcptr src)
    177 {
    178   mp_size_t  dprec = PREC(dst);
    179   mp_size_t  ssize = ABSIZ(src);
    180   unsigned long  ret;
    181 
    182   refmpf_set_prec_limbs (dst, (unsigned long) MAX (dprec, ssize));
    183   mpf_set (dst, src);
    184 
    185   ret = mpf_get_prec (dst);
    186   PREC(dst) = dprec;
    187   return ret;
    188 }
    189 
    190 /* Like mpf_set_prec, but taking a precision in limbs.
    191    PREC(f) ends up as the given "prec" value.  */
    192 void
    193 refmpf_set_prec_limbs (mpf_ptr f, unsigned long prec)
    194 {
    195   mpf_set_prec (f, __GMPF_PREC_TO_BITS (prec));
    196 }
    197 
    198 
    199 void
    200 refmpf_sub (mpf_ptr w, mpf_srcptr u, mpf_srcptr v)
    201 {
    202   mp_size_t hi, lo, size;
    203   mp_ptr ut, vt, wt;
    204   int neg;
    205   mp_exp_t exp;
    206   TMP_DECL;
    207 
    208   TMP_MARK;
    209 
    210   if (SIZ (u) == 0)
    211     {
    212       size = ABSIZ (v);
    213       wt = TMP_ALLOC_LIMBS (size + 1);
    214       MPN_COPY (wt, PTR (v), size);
    215       exp = EXP (v);
    216       neg = SIZ (v) > 0;
    217       goto done;
    218     }
    219   if (SIZ (v) == 0)
    220     {
    221       size = ABSIZ (u);
    222       wt = TMP_ALLOC_LIMBS (size + 1);
    223       MPN_COPY (wt, PTR (u), size);
    224       exp = EXP (u);
    225       neg = SIZ (u) < 0;
    226       goto done;
    227     }
    228   if ((SIZ (u) ^ SIZ (v)) < 0)
    229     {
    230       mpf_t tmp;
    231       SIZ (tmp) = -SIZ (v);
    232       EXP (tmp) = EXP (v);
    233       PTR (tmp) = PTR (v);
    234       refmpf_add (w, u, tmp);
    235       if (SIZ (u) < 0)
    236 	mpf_neg (w, w);
    237       return;
    238     }
    239   neg = SIZ (u) < 0;
    240 
    241   /* Compute the significance of the hi and lo end of the result.  */
    242   hi = MAX (EXP (u), EXP (v));
    243   lo = MIN (EXP (u) - ABSIZ (u), EXP (v) - ABSIZ (v));
    244   size = hi - lo;
    245   ut = TMP_ALLOC_LIMBS (size + 1);
    246   vt = TMP_ALLOC_LIMBS (size + 1);
    247   wt = TMP_ALLOC_LIMBS (size + 1);
    248   MPN_ZERO (ut, size);
    249   MPN_ZERO (vt, size);
    250   {int off;
    251   off = size + (EXP (u) - hi) - ABSIZ (u);
    252   MPN_COPY (ut + off, PTR (u), ABSIZ (u));
    253   off = size + (EXP (v) - hi) - ABSIZ (v);
    254   MPN_COPY (vt + off, PTR (v), ABSIZ (v));
    255   }
    256 
    257   if (mpn_cmp (ut, vt, size) >= 0)
    258     mpn_sub_n (wt, ut, vt, size);
    259   else
    260     {
    261       mpn_sub_n (wt, vt, ut, size);
    262       neg ^= 1;
    263     }
    264   exp = hi;
    265   while (size != 0 && wt[size - 1] == 0)
    266     {
    267       size--;
    268       exp--;
    269     }
    270 
    271 done:
    272   if (size > PREC (w))
    273     {
    274       wt += size - PREC (w);
    275       size = PREC (w);
    276     }
    277   MPN_COPY (PTR (w), wt, size);
    278   SIZ (w) = neg == 0 ? size : -size;
    279   EXP (w) = exp;
    280   TMP_FREE;
    281 }
    282 
    283 
    284 /* Validate got by comparing to want.  Return 1 if good, 0 if bad.
    285 
    286    The data in got is compared to that in want, up to either PREC(got) limbs
    287    or the size of got, whichever is bigger.  Clearly we always demand
    288    PREC(got) of accuracy, but we go further and say that if got is bigger
    289    then any extra must be correct too.
    290 
    291    want needs to have enough data to allow this comparison.  The size in
    292    want doesn't have to be that big though, if it's smaller then further low
    293    limbs are taken to be zero.
    294 
    295    This validation approach is designed to allow some flexibility in exactly
    296    how much data is generated by an mpf function, ie. either prec or prec+1
    297    limbs.  We don't try to make a reference function that emulates that same
    298    size decision, instead the idea is for a validation function to generate
    299    at least as much data as the real function, then compare.  */
    300 
    301 int
    302 refmpf_validate (const char *name, mpf_srcptr got, mpf_srcptr want)
    303 {
    304   int  bad = 0;
    305   mp_size_t  gsize, wsize, cmpsize, i;
    306   mp_srcptr  gp, wp;
    307   mp_limb_t  glimb, wlimb;
    308 
    309   MPF_CHECK_FORMAT (got);
    310 
    311   if (EXP (got) != EXP (want))
    312     {
    313       printf ("%s: wrong exponent\n", name);
    314       bad = 1;
    315     }
    316 
    317   gsize = SIZ (got);
    318   wsize = SIZ (want);
    319   if ((gsize < 0 && wsize > 0) || (gsize > 0 && wsize < 0))
    320     {
    321       printf ("%s: wrong sign\n", name);
    322       bad = 1;
    323     }
    324 
    325   gsize = ABS (gsize);
    326   wsize = ABS (wsize);
    327 
    328   /* most significant limb of respective data */
    329   gp = PTR (got) + gsize - 1;
    330   wp = PTR (want) + wsize - 1;
    331 
    332   /* compare limb data */
    333   cmpsize = MAX (PREC (got), gsize);
    334   for (i = 0; i < cmpsize; i++)
    335     {
    336       glimb = (i < gsize ? gp[-i] : 0);
    337       wlimb = (i < wsize ? wp[-i] : 0);
    338 
    339       if (glimb != wlimb)
    340         {
    341           printf ("%s: wrong data starting at index %ld from top\n",
    342                   name, (long) i);
    343           bad = 1;
    344           break;
    345         }
    346     }
    347 
    348   if (bad)
    349     {
    350       printf ("  prec       %d\n", PREC(got));
    351       printf ("  exp got    %ld\n", (long) EXP(got));
    352       printf ("  exp want   %ld\n", (long) EXP(want));
    353       printf ("  size got   %d\n", SIZ(got));
    354       printf ("  size want  %d\n", SIZ(want));
    355       printf ("  limbs (high to low)\n");
    356       printf ("   got  ");
    357       for (i = ABSIZ(got)-1; i >= 0; i--)
    358         {
    359           gmp_printf ("%MX", PTR(got)[i]);
    360           if (i != 0)
    361             printf (",");
    362         }
    363       printf ("\n");
    364       printf ("   want ");
    365       for (i = ABSIZ(want)-1; i >= 0; i--)
    366         {
    367           gmp_printf ("%MX", PTR(want)[i]);
    368           if (i != 0)
    369             printf (",");
    370         }
    371       printf ("\n");
    372       return 0;
    373     }
    374 
    375   return 1;
    376 }
    377 
    378 
    379 int
    380 refmpf_validate_division (const char *name, mpf_srcptr got,
    381                           mpf_srcptr n, mpf_srcptr d)
    382 {
    383   mp_size_t  nsize, dsize, sign, prec, qsize, tsize;
    384   mp_srcptr  np, dp;
    385   mp_ptr     tp, qp, rp;
    386   mpf_t      want;
    387   int        ret;
    388 
    389   nsize = SIZ (n);
    390   dsize = SIZ (d);
    391   ASSERT_ALWAYS (dsize != 0);
    392 
    393   sign = nsize ^ dsize;
    394   nsize = ABS (nsize);
    395   dsize = ABS (dsize);
    396 
    397   np = PTR (n);
    398   dp = PTR (d);
    399   prec = PREC (got);
    400 
    401   EXP (want) = EXP (n) - EXP (d) + 1;
    402 
    403   qsize = prec + 2;            /* at least prec+1 limbs, after high zero */
    404   tsize = qsize + dsize - 1;   /* dividend size to give desired qsize */
    405 
    406   /* dividend n, extended or truncated */
    407   tp = refmpn_malloc_limbs (tsize);
    408   refmpn_copy_extend (tp, tsize, np, nsize);
    409 
    410   qp = refmpn_malloc_limbs (qsize);
    411   rp = refmpn_malloc_limbs (dsize);  /* remainder, unused */
    412 
    413   ASSERT_ALWAYS (qsize == tsize - dsize + 1);
    414   refmpn_tdiv_qr (qp, rp, (mp_size_t) 0, tp, tsize, dp, dsize);
    415 
    416   PTR (want) = qp;
    417   SIZ (want) = (sign >= 0 ? qsize : -qsize);
    418   refmpf_normalize (want);
    419 
    420   ret = refmpf_validate (name, got, want);
    421 
    422   free (tp);
    423   free (qp);
    424   free (rp);
    425 
    426   return ret;
    427 }
    428