[BACK]Return to powm_ui.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / mpz

Annotation of OpenXM_contrib/gmp/mpz/powm_ui.c, Revision 1.1.1.1

1.1       maekawa     1: /* mpz_powm_ui(res,base,exp,mod) -- Set RES to (base**exp) mod MOD.
                      2:
                      3: Copyright (C) 1991, 1993, 1994, 1996 Free Software Foundation, Inc.
                      4:
                      5: This file is part of the GNU MP Library.
                      6:
                      7: The GNU MP Library is free software; you can redistribute it and/or modify
                      8: it under the terms of the GNU Library General Public License as published by
                      9: the Free Software Foundation; either version 2 of the License, or (at your
                     10: option) any later version.
                     11:
                     12: The GNU MP Library is distributed in the hope that it will be useful, but
                     13: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     14: or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
                     15: License for more details.
                     16:
                     17: You should have received a copy of the GNU Library General Public License
                     18: along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
                     19: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
                     20: MA 02111-1307, USA. */
                     21:
                     22: #include "gmp.h"
                     23: #include "gmp-impl.h"
                     24: #include "longlong.h"
                     25:
                     26: void
                     27: #if __STDC__
                     28: mpz_powm_ui (mpz_ptr res, mpz_srcptr base, unsigned long int exp, mpz_srcptr mod)
                     29: #else
                     30: mpz_powm_ui (res, base, exp, mod)
                     31:      mpz_ptr res;
                     32:      mpz_srcptr base;
                     33:      unsigned long int exp;
                     34:      mpz_srcptr mod;
                     35: #endif
                     36: {
                     37:   mp_ptr rp, mp, bp;
                     38:   mp_size_t msize, bsize, rsize;
                     39:   mp_size_t size;
                     40:   int mod_shift_cnt;
                     41:   int negative_result;
                     42:   mp_limb_t *free_me = NULL;
                     43:   size_t free_me_size;
                     44:   TMP_DECL (marker);
                     45:
                     46:   msize = ABS (mod->_mp_size);
                     47:   size = 2 * msize;
                     48:
                     49:   rp = res->_mp_d;
                     50:
                     51:   if (msize == 0)
                     52:     msize = 1 / msize;         /* provoke a signal */
                     53:
                     54:   if (exp == 0)
                     55:     {
                     56:       rp[0] = 1;
                     57:       res->_mp_size = (msize == 1 && (mod->_mp_d)[0] == 1) ? 0 : 1;
                     58:       return;
                     59:     }
                     60:
                     61:   TMP_MARK (marker);
                     62:
                     63:   /* Normalize MOD (i.e. make its most significant bit set) as required by
                     64:      mpn_divmod.  This will make the intermediate values in the calculation
                     65:      slightly larger, but the correct result is obtained after a final
                     66:      reduction using the original MOD value.  */
                     67:
                     68:   mp = (mp_ptr) TMP_ALLOC (msize * BYTES_PER_MP_LIMB);
                     69:   count_leading_zeros (mod_shift_cnt, mod->_mp_d[msize - 1]);
                     70:   if (mod_shift_cnt != 0)
                     71:     mpn_lshift (mp, mod->_mp_d, msize, mod_shift_cnt);
                     72:   else
                     73:     MPN_COPY (mp, mod->_mp_d, msize);
                     74:
                     75:   bsize = ABS (base->_mp_size);
                     76:   if (bsize > msize)
                     77:     {
                     78:       /* The base is larger than the module.  Reduce it.  */
                     79:
                     80:       /* Allocate (BSIZE + 1) with space for remainder and quotient.
                     81:         (The quotient is (bsize - msize + 1) limbs.)  */
                     82:       bp = (mp_ptr) TMP_ALLOC ((bsize + 1) * BYTES_PER_MP_LIMB);
                     83:       MPN_COPY (bp, base->_mp_d, bsize);
                     84:       /* We don't care about the quotient, store it above the remainder,
                     85:         at BP + MSIZE.  */
                     86:       mpn_divmod (bp + msize, bp, bsize, mp, msize);
                     87:       bsize = msize;
                     88:       /* Canonicalize the base, since we are going to multiply with it
                     89:         quite a few times.  */
                     90:       MPN_NORMALIZE (bp, bsize);
                     91:     }
                     92:   else
                     93:     bp = base->_mp_d;
                     94:
                     95:   if (bsize == 0)
                     96:     {
                     97:       res->_mp_size = 0;
                     98:       TMP_FREE (marker);
                     99:       return;
                    100:     }
                    101:
                    102:   if (res->_mp_alloc < size)
                    103:     {
                    104:       /* We have to allocate more space for RES.  If any of the input
                    105:         parameters are identical to RES, defer deallocation of the old
                    106:         space.  */
                    107:
                    108:       if (rp == mp || rp == bp)
                    109:        {
                    110:          free_me = rp;
                    111:          free_me_size = res->_mp_alloc;
                    112:        }
                    113:       else
                    114:        (*_mp_free_func) (rp, res->_mp_alloc * BYTES_PER_MP_LIMB);
                    115:
                    116:       rp = (mp_ptr) (*_mp_allocate_func) (size * BYTES_PER_MP_LIMB);
                    117:       res->_mp_alloc = size;
                    118:       res->_mp_d = rp;
                    119:     }
                    120:   else
                    121:     {
                    122:       /* Make BASE, EXP and MOD not overlap with RES.  */
                    123:       if (rp == bp)
                    124:        {
                    125:          /* RES and BASE are identical.  Allocate temp. space for BASE.  */
                    126:          bp = (mp_ptr) TMP_ALLOC (bsize * BYTES_PER_MP_LIMB);
                    127:          MPN_COPY (bp, rp, bsize);
                    128:        }
                    129:       if (rp == mp)
                    130:        {
                    131:          /* RES and MOD are identical.  Allocate temporary space for MOD.  */
                    132:          mp = (mp_ptr) TMP_ALLOC (msize * BYTES_PER_MP_LIMB);
                    133:          MPN_COPY (mp, rp, msize);
                    134:        }
                    135:     }
                    136:
                    137:   MPN_COPY (rp, bp, bsize);
                    138:   rsize = bsize;
                    139:
                    140:   {
                    141:     mp_ptr xp = (mp_ptr) TMP_ALLOC (2 * (msize + 1) * BYTES_PER_MP_LIMB);
                    142:     int c;
                    143:     mp_limb_t e;
                    144:     mp_limb_t carry_limb;
                    145:
                    146:     negative_result = (exp & 1) && base->_mp_size < 0;
                    147:
                    148:     e = exp;
                    149:     count_leading_zeros (c, e);
                    150:     e = (e << c) << 1;         /* shift the exp bits to the left, lose msb */
                    151:     c = BITS_PER_MP_LIMB - 1 - c;
                    152:
                    153:     /* Main loop.
                    154:
                    155:        Make the result be pointed to alternately by XP and RP.  This
                    156:        helps us avoid block copying, which would otherwise be necessary
                    157:        with the overlap restrictions of mpn_divmod.  With 50% probability
                    158:        the result after this loop will be in the area originally pointed
                    159:        by RP (==RES->_mp_d), and with 50% probability in the area originally
                    160:        pointed to by XP.  */
                    161:
                    162:     while (c != 0)
                    163:       {
                    164:        mp_ptr tp;
                    165:        mp_size_t xsize;
                    166:
                    167:        mpn_mul_n (xp, rp, rp, rsize);
                    168:        xsize = 2 * rsize;
                    169:        if (xsize > msize)
                    170:          {
                    171:            mpn_divmod (xp + msize, xp, xsize, mp, msize);
                    172:            xsize = msize;
                    173:          }
                    174:
                    175:        tp = rp; rp = xp; xp = tp;
                    176:        rsize = xsize;
                    177:
                    178:        if ((mp_limb_signed_t) e < 0)
                    179:          {
                    180:            mpn_mul (xp, rp, rsize, bp, bsize);
                    181:            xsize = rsize + bsize;
                    182:            if (xsize > msize)
                    183:              {
                    184:                mpn_divmod (xp + msize, xp, xsize, mp, msize);
                    185:                xsize = msize;
                    186:              }
                    187:
                    188:            tp = rp; rp = xp; xp = tp;
                    189:            rsize = xsize;
                    190:          }
                    191:        e <<= 1;
                    192:        c--;
                    193:       }
                    194:
                    195:     /* We shifted MOD, the modulo reduction argument, left MOD_SHIFT_CNT
                    196:        steps.  Adjust the result by reducing it with the original MOD.
                    197:
                    198:        Also make sure the result is put in RES->_mp_d (where it already
                    199:        might be, see above).  */
                    200:
                    201:     if (mod_shift_cnt != 0)
                    202:       {
                    203:        carry_limb = mpn_lshift (res->_mp_d, rp, rsize, mod_shift_cnt);
                    204:        rp = res->_mp_d;
                    205:        if (carry_limb != 0)
                    206:          {
                    207:            rp[rsize] = carry_limb;
                    208:            rsize++;
                    209:          }
                    210:       }
                    211:     else
                    212:       {
                    213:        MPN_COPY (res->_mp_d, rp, rsize);
                    214:        rp = res->_mp_d;
                    215:       }
                    216:
                    217:     if (rsize >= msize)
                    218:       {
                    219:        mpn_divmod (rp + msize, rp, rsize, mp, msize);
                    220:        rsize = msize;
                    221:       }
                    222:
                    223:     /* Remove any leading zero words from the result.  */
                    224:     if (mod_shift_cnt != 0)
                    225:       mpn_rshift (rp, rp, rsize, mod_shift_cnt);
                    226:     MPN_NORMALIZE (rp, rsize);
                    227:   }
                    228:
                    229:   res->_mp_size = negative_result == 0 ? rsize : -rsize;
                    230:
                    231:   if (free_me != NULL)
                    232:     (*_mp_free_func) (free_me, free_me_size * BYTES_PER_MP_LIMB);
                    233:   TMP_FREE (marker);
                    234: }

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