Annotation of OpenXM/src/kan96xx/gmp-2.0.2/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>