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

Annotation of OpenXM_contrib/gmp/mpz/powm.c, Revision 1.1

1.1     ! maekawa     1: /* mpz_powm(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: #ifndef BERKELEY_MP
        !            27: void
        !            28: #if __STDC__
        !            29: mpz_powm (mpz_ptr res, mpz_srcptr base, mpz_srcptr exp, mpz_srcptr mod)
        !            30: #else
        !            31: mpz_powm (res, base, exp, mod)
        !            32:      mpz_ptr res;
        !            33:      mpz_srcptr base;
        !            34:      mpz_srcptr exp;
        !            35:      mpz_srcptr mod;
        !            36: #endif
        !            37: #else /* BERKELEY_MP */
        !            38: void
        !            39: #if __STDC__
        !            40: pow (mpz_srcptr base, mpz_srcptr exp, mpz_srcptr mod, mpz_ptr res)
        !            41: #else
        !            42: pow (base, exp, mod, res)
        !            43:      mpz_srcptr base;
        !            44:      mpz_srcptr exp;
        !            45:      mpz_srcptr mod;
        !            46:      mpz_ptr res;
        !            47: #endif
        !            48: #endif /* BERKELEY_MP */
        !            49: {
        !            50:   mp_ptr rp, ep, mp, bp;
        !            51:   mp_size_t esize, msize, bsize, rsize;
        !            52:   mp_size_t size;
        !            53:   int mod_shift_cnt;
        !            54:   int negative_result;
        !            55:   mp_limb_t *free_me = NULL;
        !            56:   size_t free_me_size;
        !            57:   TMP_DECL (marker);
        !            58:
        !            59:   esize = ABS (exp->_mp_size);
        !            60:   msize = ABS (mod->_mp_size);
        !            61:   size = 2 * msize;
        !            62:
        !            63:   rp = res->_mp_d;
        !            64:   ep = exp->_mp_d;
        !            65:
        !            66:   if (msize == 0)
        !            67:     msize = 1 / msize;         /* provoke a signal */
        !            68:
        !            69:   if (esize == 0)
        !            70:     {
        !            71:       /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0
        !            72:         depending on if MOD equals 1.  */
        !            73:       rp[0] = 1;
        !            74:       res->_mp_size = (msize == 1 && (mod->_mp_d)[0] == 1) ? 0 : 1;
        !            75:       return;
        !            76:     }
        !            77:
        !            78:   TMP_MARK (marker);
        !            79:
        !            80:   /* Normalize MOD (i.e. make its most significant bit set) as required by
        !            81:      mpn_divmod.  This will make the intermediate values in the calculation
        !            82:      slightly larger, but the correct result is obtained after a final
        !            83:      reduction using the original MOD value.  */
        !            84:
        !            85:   mp = (mp_ptr) TMP_ALLOC (msize * BYTES_PER_MP_LIMB);
        !            86:   count_leading_zeros (mod_shift_cnt, mod->_mp_d[msize - 1]);
        !            87:   if (mod_shift_cnt != 0)
        !            88:     mpn_lshift (mp, mod->_mp_d, msize, mod_shift_cnt);
        !            89:   else
        !            90:     MPN_COPY (mp, mod->_mp_d, msize);
        !            91:
        !            92:   bsize = ABS (base->_mp_size);
        !            93:   if (bsize > msize)
        !            94:     {
        !            95:       /* The base is larger than the module.  Reduce it.  */
        !            96:
        !            97:       /* Allocate (BSIZE + 1) with space for remainder and quotient.
        !            98:         (The quotient is (bsize - msize + 1) limbs.)  */
        !            99:       bp = (mp_ptr) TMP_ALLOC ((bsize + 1) * BYTES_PER_MP_LIMB);
        !           100:       MPN_COPY (bp, base->_mp_d, bsize);
        !           101:       /* We don't care about the quotient, store it above the remainder,
        !           102:         at BP + MSIZE.  */
        !           103:       mpn_divmod (bp + msize, bp, bsize, mp, msize);
        !           104:       bsize = msize;
        !           105:       /* Canonicalize the base, since we are going to multiply with it
        !           106:         quite a few times.  */
        !           107:       MPN_NORMALIZE (bp, bsize);
        !           108:     }
        !           109:   else
        !           110:     bp = base->_mp_d;
        !           111:
        !           112:   if (bsize == 0)
        !           113:     {
        !           114:       res->_mp_size = 0;
        !           115:       TMP_FREE (marker);
        !           116:       return;
        !           117:     }
        !           118:
        !           119:   if (res->_mp_alloc < size)
        !           120:     {
        !           121:       /* We have to allocate more space for RES.  If any of the input
        !           122:         parameters are identical to RES, defer deallocation of the old
        !           123:         space.  */
        !           124:
        !           125:       if (rp == ep || rp == mp || rp == bp)
        !           126:        {
        !           127:          free_me = rp;
        !           128:          free_me_size = res->_mp_alloc;
        !           129:        }
        !           130:       else
        !           131:        (*_mp_free_func) (rp, res->_mp_alloc * BYTES_PER_MP_LIMB);
        !           132:
        !           133:       rp = (mp_ptr) (*_mp_allocate_func) (size * BYTES_PER_MP_LIMB);
        !           134:       res->_mp_alloc = size;
        !           135:       res->_mp_d = rp;
        !           136:     }
        !           137:   else
        !           138:     {
        !           139:       /* Make BASE, EXP and MOD not overlap with RES.  */
        !           140:       if (rp == bp)
        !           141:        {
        !           142:          /* RES and BASE are identical.  Allocate temp. space for BASE.  */
        !           143:          bp = (mp_ptr) TMP_ALLOC (bsize * BYTES_PER_MP_LIMB);
        !           144:          MPN_COPY (bp, rp, bsize);
        !           145:        }
        !           146:       if (rp == ep)
        !           147:        {
        !           148:          /* RES and EXP are identical.  Allocate temp. space for EXP.  */
        !           149:          ep = (mp_ptr) TMP_ALLOC (esize * BYTES_PER_MP_LIMB);
        !           150:          MPN_COPY (ep, rp, esize);
        !           151:        }
        !           152:       if (rp == mp)
        !           153:        {
        !           154:          /* RES and MOD are identical.  Allocate temporary space for MOD.  */
        !           155:          mp = (mp_ptr) TMP_ALLOC (msize * BYTES_PER_MP_LIMB);
        !           156:          MPN_COPY (mp, rp, msize);
        !           157:        }
        !           158:     }
        !           159:
        !           160:   MPN_COPY (rp, bp, bsize);
        !           161:   rsize = bsize;
        !           162:
        !           163:   {
        !           164:     mp_size_t i;
        !           165:     mp_ptr xp = (mp_ptr) TMP_ALLOC (2 * (msize + 1) * BYTES_PER_MP_LIMB);
        !           166:     int c;
        !           167:     mp_limb_t e;
        !           168:     mp_limb_t carry_limb;
        !           169:
        !           170:     negative_result = (ep[0] & 1) && base->_mp_size < 0;
        !           171:
        !           172:     i = esize - 1;
        !           173:     e = ep[i];
        !           174:     count_leading_zeros (c, e);
        !           175:     e = (e << c) << 1;         /* shift the exp bits to the left, lose msb */
        !           176:     c = BITS_PER_MP_LIMB - 1 - c;
        !           177:
        !           178:     /* Main loop.
        !           179:
        !           180:        Make the result be pointed to alternately by XP and RP.  This
        !           181:        helps us avoid block copying, which would otherwise be necessary
        !           182:        with the overlap restrictions of mpn_divmod.  With 50% probability
        !           183:        the result after this loop will be in the area originally pointed
        !           184:        by RP (==RES->_mp_d), and with 50% probability in the area originally
        !           185:        pointed to by XP.  */
        !           186:
        !           187:     for (;;)
        !           188:       {
        !           189:        while (c != 0)
        !           190:          {
        !           191:            mp_ptr tp;
        !           192:            mp_size_t xsize;
        !           193:
        !           194:            mpn_mul_n (xp, rp, rp, rsize);
        !           195:            xsize = 2 * rsize;
        !           196:            if (xsize > msize)
        !           197:              {
        !           198:                mpn_divmod (xp + msize, xp, xsize, mp, msize);
        !           199:                xsize = msize;
        !           200:              }
        !           201:
        !           202:            tp = rp; rp = xp; xp = tp;
        !           203:            rsize = xsize;
        !           204:
        !           205:            if ((mp_limb_signed_t) e < 0)
        !           206:              {
        !           207:                mpn_mul (xp, rp, rsize, bp, bsize);
        !           208:                xsize = rsize + bsize;
        !           209:                if (xsize > msize)
        !           210:                  {
        !           211:                    mpn_divmod (xp + msize, xp, xsize, mp, msize);
        !           212:                    xsize = msize;
        !           213:                  }
        !           214:
        !           215:                tp = rp; rp = xp; xp = tp;
        !           216:                rsize = xsize;
        !           217:              }
        !           218:            e <<= 1;
        !           219:            c--;
        !           220:          }
        !           221:
        !           222:        i--;
        !           223:        if (i < 0)
        !           224:          break;
        !           225:        e = ep[i];
        !           226:        c = BITS_PER_MP_LIMB;
        !           227:       }
        !           228:
        !           229:     /* We shifted MOD, the modulo reduction argument, left MOD_SHIFT_CNT
        !           230:        steps.  Adjust the result by reducing it with the original MOD.
        !           231:
        !           232:        Also make sure the result is put in RES->_mp_d (where it already
        !           233:        might be, see above).  */
        !           234:
        !           235:     if (mod_shift_cnt != 0)
        !           236:       {
        !           237:        carry_limb = mpn_lshift (res->_mp_d, rp, rsize, mod_shift_cnt);
        !           238:        rp = res->_mp_d;
        !           239:        if (carry_limb != 0)
        !           240:          {
        !           241:            rp[rsize] = carry_limb;
        !           242:            rsize++;
        !           243:          }
        !           244:       }
        !           245:     else
        !           246:       {
        !           247:        MPN_COPY (res->_mp_d, rp, rsize);
        !           248:        rp = res->_mp_d;
        !           249:       }
        !           250:
        !           251:     if (rsize >= msize)
        !           252:       {
        !           253:        mpn_divmod (rp + msize, rp, rsize, mp, msize);
        !           254:        rsize = msize;
        !           255:       }
        !           256:
        !           257:     /* Remove any leading zero words from the result.  */
        !           258:     if (mod_shift_cnt != 0)
        !           259:       mpn_rshift (rp, rp, rsize, mod_shift_cnt);
        !           260:     MPN_NORMALIZE (rp, rsize);
        !           261:   }
        !           262:
        !           263:   if (negative_result && rsize != 0)
        !           264:     {
        !           265:       if (mod_shift_cnt != 0)
        !           266:        mpn_rshift (mp, mp, msize, mod_shift_cnt);
        !           267:       mpn_sub (rp, mp, msize, rp, rsize);
        !           268:       rsize = msize;
        !           269:       MPN_NORMALIZE (rp, rsize);
        !           270:     }
        !           271:   res->_mp_size = rsize;
        !           272:
        !           273:   if (free_me != NULL)
        !           274:     (*_mp_free_func) (free_me, free_me_size * BYTES_PER_MP_LIMB);
        !           275:   TMP_FREE (marker);
        !           276: }

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