[BACK]Return to rootrem.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / mpn / generic

Annotation of OpenXM_contrib/gmp/mpn/generic/rootrem.c, Revision 1.1.1.1

1.1       ohara       1: /* mpn_rootrem(rootp,remp,ap,an,nth) -- Compute the nth root of {ap,an}, and
                      2:    store the truncated integer part at rootp and the remainder at remp.
                      3:
                      4:    THE FUNCTIONS IN THIS FILE ARE INTERNAL FUNCTIONS WITH MUTABLE
                      5:    INTERFACES.  IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.
                      6:    IN FACT, IT IS ALMOST GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A
                      7:    FUTURE GNU MP RELEASE.
                      8:
                      9:
                     10: Copyright 2002 Free Software Foundation, Inc.
                     11:
                     12: This file is part of the GNU MP Library.
                     13:
                     14: The GNU MP Library is free software; you can redistribute it and/or modify
                     15: it under the terms of the GNU Lesser General Public License as published by
                     16: the Free Software Foundation; either version 2.1 of the License, or (at your
                     17: option) any later version.
                     18:
                     19: The GNU MP Library is distributed in the hope that it will be useful, but
                     20: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     21: or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
                     22: License for more details.
                     23:
                     24: You should have received a copy of the GNU Lesser General Public License
                     25: along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
                     26: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
                     27: MA 02111-1307, USA. */
                     28:
                     29: /*
                     30:   We use Newton's method to compute the root of a:
                     31:
                     32:            n
                     33:   f(x) := x  - a
                     34:
                     35:
                     36:             n - 1
                     37:   f'(x) := x      n
                     38:
                     39:
                     40:                                        n-1            n-1           n-1
                     41:                                 x - a/x            a/x   - x     a/x   + (n-1)x
                     42:   new x = x - f(x)/f'(x) =  x - ----------  =  x + ---------  =  --------------
                     43:                                      n                 n                n
                     44:
                     45: */
                     46:
                     47:
                     48: #include <stdio.h>
                     49: #include <stdlib.h>
                     50:
                     51: #include "gmp.h"
                     52: #include "gmp-impl.h"
                     53: #include "longlong.h"
                     54:
                     55: mp_size_t
                     56: mpn_rootrem (mp_ptr rootp, mp_ptr remp,
                     57:             mp_srcptr up, mp_size_t un, mp_limb_t nth)
                     58: {
                     59:   mp_ptr pp, qp, xp;
                     60:   mp_size_t pn, xn, qn;
                     61:   unsigned long int unb, xnb, bit;
                     62:   unsigned int cnt;
                     63:   mp_size_t i;
                     64:   unsigned long int n_valid_bits, adj;
                     65:   TMP_DECL (marker);
                     66:
                     67:   TMP_MARK (marker);
                     68:
                     69:   /* The extra factor 1.585 = log(3)/log(2) here is for the worst case
                     70:      overestimate of the root, i.e., when the code rounds a root that is
                     71:      2+epsilon to 3, and the powers this to a potentially huge power.  We
                     72:      could generalize the code for detecting root=1 a few lines below to deal
                     73:      with xnb <= k, for some small k.  For example, when xnb <= 2, meaning
                     74:      the root should be 1, 2, or 3, we could replace this factor by the much
                     75:      smaller log(5)/log(4).  */
                     76:
                     77: #define PP_ALLOC (2 + (mp_size_t) (un*1.585))
                     78:   pp = TMP_ALLOC_LIMBS (PP_ALLOC);
                     79:
                     80:   count_leading_zeros (cnt, up[un - 1]);
                     81:   unb = un * GMP_NUMB_BITS - cnt + GMP_NAIL_BITS;
                     82:
                     83:   xnb = (unb - 1) / nth + 1;
                     84:   if (xnb == 1)
                     85:     {
                     86:       if (remp == NULL)
                     87:        remp = pp;
                     88:       mpn_sub_1 (remp, up, un, (mp_limb_t) 1);
                     89:       MPN_NORMALIZE (remp, un);
                     90:       rootp[0] = 1;
                     91:       TMP_FREE (marker);
                     92:       return un;
                     93:     }
                     94:
                     95:   xn = (xnb + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS;
                     96:
                     97:   qp = TMP_ALLOC_LIMBS (un + 1);
                     98:   xp = TMP_ALLOC_LIMBS (xn + 1);
                     99:
                    100:   /* Set initial root to only ones.  This is an overestimate of the actual root
                    101:      by less than a factor of 2.  */
                    102:   for (i = 0; i < xn; i++)
                    103:     xp[i] = GMP_NUMB_MAX;
                    104:   xp[xnb / GMP_NUMB_BITS] = ((mp_limb_t) 1 << (xnb % GMP_NUMB_BITS)) - 1;
                    105:
                    106:   /* Improve the initial approximation, one bit at a time.  Keep the
                    107:      approximations >= root(U,nth).  */
                    108:   bit = xnb - 2;
                    109:   n_valid_bits = 0;
                    110:   for (i = 0; (nth >> i) != 0; i++)
                    111:     {
                    112:       mp_limb_t xl = xp[bit / GMP_NUMB_BITS];
                    113:       xp[bit / GMP_NUMB_BITS] = xl ^ (mp_limb_t) 1 << bit % GMP_NUMB_BITS;
                    114:       pn = mpn_pow_1 (pp, xp, xn, nth, qp);
                    115:       ASSERT_ALWAYS (pn < PP_ALLOC);
                    116:       /* If the new root approximation is too small, restore old value.  */
                    117:       if (! (un < pn || (un == pn && mpn_cmp (up, pp, pn) < 0)))
                    118:        xp[bit / GMP_NUMB_BITS] = xl;           /* restore old value */
                    119:       n_valid_bits += 1;
                    120:       if (bit == 0)
                    121:        goto done;
                    122:       bit--;
                    123:     }
                    124:
                    125:   adj = n_valid_bits - 1;
                    126:
                    127:   /* Newton loop.  Converges downwards towards root(U,nth).  Currently we use
                    128:    full precision from iteration 1.  Clearly, we should use just n_valid_bits
                    129:    of precision in each step, and thus save most of the computations.  */
                    130:   while (n_valid_bits <= xnb)
                    131:     {
                    132:       mp_limb_t cy;
                    133:
                    134:       pn = mpn_pow_1 (pp, xp, xn, nth - 1, qp);
                    135:       ASSERT_ALWAYS (pn < PP_ALLOC);
                    136:       qp[xn - 1] = 0;          /* pad quotient to make it always xn limbs */
                    137:       mpn_tdiv_qr (qp, pp, (mp_size_t) 0, up, un, pp, pn); /* junk remainder */
                    138:       cy = mpn_addmul_1 (qp, xp, xn, nth - 1);
                    139:       if (un - pn == xn)
                    140:        {
                    141:          cy += qp[xn];
                    142:          if (cy == nth)
                    143:            {
                    144:              for (i = xn - 1; i >= 0; i--)
                    145:                qp[i] = GMP_NUMB_MAX;
                    146:              cy = nth - 1;
                    147:            }
                    148:        }
                    149:
                    150:       qp[xn] = cy;
                    151:       qn = xn + (cy != 0);
                    152:
                    153:       mpn_divrem_1 (xp, (mp_size_t) 0, qp, qn, nth);
                    154:       n_valid_bits = n_valid_bits * 2 - adj;
                    155:     }
                    156:
                    157:   /* The computed result might be one unit too large.  Adjust as necessary.  */
                    158:  done:
                    159:   pn = mpn_pow_1 (pp, xp, xn, nth, qp);
                    160:   ASSERT_ALWAYS (pn < PP_ALLOC);
                    161:   if (un < pn || (un == pn && mpn_cmp (up, pp, pn) < 0))
                    162:     {
                    163:       mpn_decr_u (xp, 1);
                    164:       pn = mpn_pow_1 (pp, xp, xn, nth, qp);
                    165:       ASSERT_ALWAYS (pn < PP_ALLOC);
                    166:
                    167:       ASSERT_ALWAYS (! (un < pn || (un == pn && mpn_cmp (up, pp, pn) < 0)));
                    168:     }
                    169:
                    170:   if (remp == NULL)
                    171:     remp = pp;
                    172:   mpn_sub (remp, up, un, pp, pn);
                    173:   MPN_NORMALIZE (remp, un);
                    174:   MPN_COPY (rootp, xp, xn);
                    175:   TMP_FREE (marker);
                    176:   return un;
                    177: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>