bn_mp_div.c

Go 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  doxygen 1.5.1