bn_mp_div.cGo to the documentation of this file.00001 #include <tommath.h> 00002 #ifdef BN_MP_DIV_C 00003 /* LibTomMath, multiple-precision integer library -- Tom St Denis 00004 * 00005 * LibTomMath is a library that provides multiple-precision 00006 * integer arithmetic as well as number theoretic functionality. 00007 * 00008 * The library was designed directly after the MPI library by 00009 * Michael Fromberger but has been written from scratch with 00010 * additional optimizations in place. 00011 * 00012 * The library is free for all purposes without any express 00013 * guarantee it works. 00014 * 00015 * Tom St Denis, tomstdenis@gmail.com, http://math.libtomcrypt.com 00016 */ 00017 00018 #ifdef BN_MP_DIV_SMALL 00019 00020 /* slower bit-bang division... also smaller */ 00021 int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d) 00022 { 00023 mp_int ta, tb, tq, q; 00024 int res, n, n2; 00025 00026 /* is divisor zero ? */ 00027 if (mp_iszero (b) == 1) { 00028 return MP_VAL; 00029 } 00030 00031 /* if a < b then q=0, r = a */ 00032 if (mp_cmp_mag (a, b) == MP_LT) { 00033 if (d != NULL) { 00034 res = mp_copy (a, d); 00035 } else { 00036 res = MP_OKAY; 00037 } 00038 if (c != NULL) { 00039 mp_zero (c); 00040 } 00041 return res; 00042 } 00043 00044 /* init our temps */ 00045 if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) { 00046 return res; 00047 } 00048 00049 00050 mp_set(&tq, 1); 00051 n = mp_count_bits(a) - mp_count_bits(b); 00052 if (((res = mp_abs(a, &ta)) != MP_OKAY) || 00053 ((res = mp_abs(b, &tb)) != MP_OKAY) || 00054 ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) || 00055 ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) { 00056 goto LBL_ERR; 00057 } 00058 00059 while (n-- >= 0) { 00060 if (mp_cmp(&tb, &ta) != MP_GT) { 00061 if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) || 00062 ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) { 00063 goto LBL_ERR; 00064 } 00065 } 00066 if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) || 00067 ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) { 00068 goto LBL_ERR; 00069 } 00070 } 00071 00072 /* now q == quotient and ta == remainder */ 00073 n = a->sign; 00074 n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG); 00075 if (c != NULL) { 00076 mp_exch(c, &q); 00077 c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2; 00078 } 00079 if (d != NULL) { 00080 mp_exch(d, &ta); 00081 d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n; 00082 } 00083 LBL_ERR: 00084 mp_clear_multi(&ta, &tb, &tq, &q, NULL); 00085 return res; 00086 } 00087 00088 #else 00089 00090 /* integer signed division. 00091 * c*b + d == a [e.g. a/b, c=quotient, d=remainder] 00092 * HAC pp.598 Algorithm 14.20 00093 * 00094 * Note that the description in HAC is horribly 00095 * incomplete. For example, it doesn't consider 00096 * the case where digits are removed from 'x' in 00097 * the inner loop. It also doesn't consider the 00098 * case that y has fewer than three digits, etc.. 00099 * 00100 * The overall algorithm is as described as 00101 * 14.20 from HAC but fixed to treat these cases. 00102 */ 00103 int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) 00104 { 00105 mp_int q, x, y, t1, t2; 00106 int res, n, t, i, norm, neg; 00107 00108 /* is divisor zero ? */ 00109 if (mp_iszero (b) == 1) { 00110 return MP_VAL; 00111 } 00112 00113 /* if a < b then q=0, r = a */ 00114 if (mp_cmp_mag (a, b) == MP_LT) { 00115 if (d != NULL) { 00116 res = mp_copy (a, d); 00117 } else { 00118 res = MP_OKAY; 00119 } 00120 if (c != NULL) { 00121 mp_zero (c); 00122 } 00123 return res; 00124 } 00125 00126 if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { 00127 return res; 00128 } 00129 q.used = a->used + 2; 00130 00131 if ((res = mp_init (&t1)) != MP_OKAY) { 00132 goto LBL_Q; 00133 } 00134 00135 if ((res = mp_init (&t2)) != MP_OKAY) { 00136 goto LBL_T1; 00137 } 00138 00139 if ((res = mp_init_copy (&x, a)) != MP_OKAY) { 00140 goto LBL_T2; 00141 } 00142 00143 if ((res = mp_init_copy (&y, b)) != MP_OKAY) { 00144 goto LBL_X; 00145 } 00146 00147 /* fix the sign */ 00148 neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; 00149 x.sign = y.sign = MP_ZPOS; 00150 00151 /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ 00152 norm = mp_count_bits(&y) % DIGIT_BIT; 00153 if (norm < (int)(DIGIT_BIT-1)) { 00154 norm = (DIGIT_BIT-1) - norm; 00155 if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { 00156 goto LBL_Y; 00157 } 00158 if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) { 00159 goto LBL_Y; 00160 } 00161 } else { 00162 norm = 0; 00163 } 00164 00165 /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ 00166 n = x.used - 1; 00167 t = y.used - 1; 00168 00169 /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ 00170 if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */ 00171 goto LBL_Y; 00172 } 00173 00174 while (mp_cmp (&x, &y) != MP_LT) { 00175 ++(q.dp[n - t]); 00176 if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) { 00177 goto LBL_Y; 00178 } 00179 } 00180 00181 /* reset y by shifting it back down */ 00182 mp_rshd (&y, n - t); 00183 00184 /* step 3. for i from n down to (t + 1) */ 00185 for (i = n; i >= (t + 1); i--) { 00186 if (i > x.used) { 00187 continue; 00188 } 00189 00190 /* step 3.1 if xi == yt then set q{i-t-1} to b-1, 00191 * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ 00192 if (x.dp[i] == y.dp[t]) { 00193 q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1); 00194 } else { 00195 mp_word tmp; 00196 tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); 00197 tmp |= ((mp_word) x.dp[i - 1]); 00198 tmp /= ((mp_word) y.dp[t]); 00199 if (tmp > (mp_word) MP_MASK) 00200 tmp = MP_MASK; 00201 q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); 00202 } 00203 00204 /* while (q{i-t-1} * (yt * b + y{t-1})) > 00205 xi * b**2 + xi-1 * b + xi-2 00206 00207 do q{i-t-1} -= 1; 00208 */ 00209 q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK; 00210 do { 00211 q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; 00212 00213 /* find left hand */ 00214 mp_zero (&t1); 00215 t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; 00216 t1.dp[1] = y.dp[t]; 00217 t1.used = 2; 00218 if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { 00219 goto LBL_Y; 00220 } 00221 00222 /* find right hand */ 00223 t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; 00224 t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; 00225 t2.dp[2] = x.dp[i]; 00226 t2.used = 3; 00227 } while (mp_cmp_mag(&t1, &t2) == MP_GT); 00228 00229 /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ 00230 if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { 00231 goto LBL_Y; 00232 } 00233 00234 if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { 00235 goto LBL_Y; 00236 } 00237 00238 if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) { 00239 goto LBL_Y; 00240 } 00241 00242 /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ 00243 if (x.sign == MP_NEG) { 00244 if ((res = mp_copy (&y, &t1)) != MP_OKAY) { 00245 goto LBL_Y; 00246 } 00247 if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { 00248 goto LBL_Y; 00249 } 00250 if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) { 00251 goto LBL_Y; 00252 } 00253 00254 q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; 00255 } 00256 } 00257 00258 /* now q is the quotient and x is the remainder 00259 * [which we have to normalize] 00260 */ 00261 00262 /* get sign before writing to c */ 00263 x.sign = x.used == 0 ? MP_ZPOS : a->sign; 00264 00265 if (c != NULL) { 00266 mp_clamp (&q); 00267 mp_exch (&q, c); 00268 c->sign = neg; 00269 } 00270 00271 if (d != NULL) { 00272 mp_div_2d (&x, norm, &x, NULL); 00273 mp_exch (&x, d); 00274 } 00275 00276 res = MP_OKAY; 00277 00278 LBL_Y:mp_clear (&y); 00279 LBL_X:mp_clear (&x); 00280 LBL_T2:mp_clear (&t2); 00281 LBL_T1:mp_clear (&t1); 00282 LBL_Q:mp_clear (&q); 00283 return res; 00284 } 00285 00286 #endif 00287 00288 #endif 00289 00290 /* $Source: /cvsroot/tcl/libtommath/bn_mp_div.c,v $ */ 00291 /* $Revision: 1.4 $ */ 00292 /* $Date: 2006/12/01 19:45:38 $ */
Generated on Wed Mar 12 12:18:24 2008 by 1.5.1 |