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