メインページ   モジュール   データ構造   ファイル一覧   データフィールド   グローバル  

div.c

解説を見る。
00001 #include "multiprec.h"
00002 #include <string.h>
00003 
00031 digit_t
00032 ymp_divmodabs_digit(digit_t *quotient, const digit_t *lhs, const digit_t rhs,
00033                     size_t lhs_len)
00034 {
00035   double_digit_t tmp = 0;
00036   register size_t i = lhs_len;
00037   
00038   while (i-- > 0)
00039     {
00040       tmp = LOW_DIGIT_TO_HIGH_DIGIT(tmp);
00041       tmp += lhs[i];
00042       if (quotient) quotient[i] = tmp/rhs;
00043       tmp %= rhs;
00044     }
00045   return LOW_DIGIT(tmp);
00046 }
00047 
00048 
00049 
00050 
00071 inline static void
00072 do_divmodabs(digit_t *quotient, digit_t *lhs, const digit_t *rhs, 
00073              size_t lhs_len, size_t rhs_len)
00074 
00075 {
00076   double_digit_t lhs_top;
00077   size_t i;
00078 
00079   i = lhs_len; lhs_top = lhs[--i];
00080   while (i-- >= rhs_len)
00081     {
00082       size_t j;
00083       digit_t q;
00084       double_digit_t tmp;
00085 
00086       /* 最上位桁による仮商を定める */
00087       lhs_top = LOW_DIGIT_TO_HIGH_DIGIT(lhs_top);
00088       lhs_top += lhs[i];
00089       q = lhs_top / rhs[rhs_len-1];
00090 
00091       /* (被除数)*(仮商) を被除数から引いてみる*/
00092       tmp = 0;
00093       for (j=0; j<rhs_len; ++j)
00094         {
00095           double_digit_t tmp2 = MULTIPREC_RADIX;
00096           tmp += ((double_digit_t)rhs[j]) * q;
00097 
00098           tmp2 += lhs[i-rhs_len+j+1];
00099           tmp2 -= LOW_DIGIT(tmp);
00100           lhs[i-rhs_len+j+1] = LOW_DIGIT(tmp2);
00101 
00102           tmp = HIGH_DIGIT(tmp);
00103           tmp += !HIGH_DIGIT(tmp2);
00104         }
00105       tmp = MULTIPREC_RADIX - tmp;
00106       tmp += lhs[i+1];
00107       lhs[i+1] = LOW_DIGIT(tmp);
00108 
00109       /* 引き過ぎていたら、最上位桁の最上位bitは1の筈 */
00110       while (lhs[i+1] & DIGIT_HIGHEST_BIT) 
00111         {
00112           /* 商を減らし */
00113           --q;
00114 
00115           /* その分だけ足し戻す */
00116           tmp = 0;
00117           for (j=0; j<rhs_len; ++j)
00118             {
00119               tmp += lhs[i-rhs_len+j+1];
00120               tmp += rhs[j];
00121               lhs[i-rhs_len+j+1] = LOW_DIGIT(tmp);
00122               tmp = HIGH_DIGIT(tmp);
00123             }
00124           lhs[i+1] += LOW_DIGIT(tmp);
00125         }
00126 
00127       /* 得られた商を書き込む */
00128       if (quotient) quotient[i+1-rhs_len] = q;
00129       
00130       lhs_top = lhs[i];
00131     }
00132 }
00133 
00134 
00135 
00158 size_t
00159 ymp_divmodabs(digit_t *quotient, digit_t *remainder,
00160               const digit_t *lhs, const digit_t *rhs,
00161               size_t lhs_len, size_t rhs_len)
00162 {
00163   int shift_width; /* シフト幅 */
00164   digit_t hd;      /* rhsの最上位桁 */
00165   size_t i;
00166   digit_t *new_lhs, *new_rhs; /* 被除数、除数を各々シフトしたもの */
00167   double_digit_t tmp;
00168 
00169   /* 0除算を弾く */
00170   if (rhs_len==0 || (rhs_len==1 && rhs[0]==0))
00171     {
00172       ymp_fatal("0による除算");
00173       return 0;
00174     }
00175 
00176   /* シフトした被除数、除数を格納するための領域を確保 */
00177   YMP_TEMP_ALLOCATE(new_lhs, digit_t, lhs_len+1);
00178   YMP_TEMP_ALLOCATE(new_rhs, digit_t, rhs_len);
00179 
00180   /* 適切なシフト幅を算出 */
00181   shift_width = 0;
00182   hd = rhs[rhs_len-1];
00183   while ( !(hd & DIGIT_HIGHEST_BIT) )
00184     {
00185       ++shift_width;
00186       hd <<= 1;
00187     }
00188 
00189   /* 除数をshift_widthだけシフト */
00190   i = rhs_len; tmp = rhs[--i];
00191   while (i-- > 0)
00192     {
00193       tmp = LOW_DIGIT_TO_HIGH_DIGIT(tmp);
00194       tmp += rhs[i];
00195       tmp <<= shift_width;
00196       new_rhs[i+1] = HIGH_DIGIT(tmp);
00197       tmp = rhs[i];
00198     }
00199   new_rhs[0] = rhs[0] << shift_width;
00200 
00201   /* 被除数をshift_widthだけシフト */
00202   tmp = 0; i=lhs_len;
00203   while(i-- > 0)
00204     {
00205       tmp += lhs[i];
00206       tmp <<= shift_width;
00207       new_lhs[i+1] = HIGH_DIGIT(tmp);
00208 
00209       tmp = lhs[i];
00210       tmp = LOW_DIGIT_TO_HIGH_DIGIT(tmp);
00211     }
00212   new_lhs[0] = lhs[0] << shift_width;
00213 
00214   /* シフトした状態で、除算を実行 */
00215   do_divmodabs(quotient, new_lhs, new_rhs, lhs_len+1, rhs_len);
00216 
00217   /* 今、シフトされた剰余がnew_lhsに入っている */
00218 
00219   if (remainder)
00220     {
00221       /* 剰余を逆シフトして復元しながら、非0の最高桁数を探す */
00222       size_t rem_used = 0;
00223       tmp = 0; i=rhs_len;
00224       while (i-- > 0)
00225         {
00226           tmp += new_lhs[i];
00227           remainder[i] = LOW_DIGIT(tmp >> shift_width);
00228 
00229           if (remainder[i] && !rem_used) rem_used = i+1;
00230 
00231           tmp = new_lhs[i];
00232           tmp = LOW_DIGIT_TO_HIGH_DIGIT(tmp);
00233         }
00234       return rem_used;
00235     }
00236   else
00237     {
00238       return 0;
00239     }
00240 }
00261 void
00262 ymp_divmod(mp_ref_t quotient, mp_ref_t remainder, 
00263            mp_cref_t self, mp_cref_t other)
00264 {
00265   enum mp_sign_t rem_sign;
00266   size_t rem_used;
00267 
00268   /* 0除算を弾く */
00269   if (ymp_is_zero(other))
00270     {
00271       ymp_fatal("0による除算");
00272       return;
00273     }
00274 
00275   /* 明らかに (被除数) < (除数) と分かる場合:
00276      商は0、剰余は被除数に等しい */
00277   if (self->used < other->used)
00278     {
00279       if (quotient) quotient->used = 0;
00280       if (self != remainder && remainder) ymp_assign(remainder, self);
00281       return;
00282     }
00283 
00284   /* 商・剰余の格納に十分な領域を確保 */
00285   if (quotient) ymp_reserve(quotient, self->used-other->used+1);
00286   if (remainder) ymp_reserve(remainder, other->used);
00287 
00288   /* 絶対値同士の除算を行う */
00289   rem_sign = self->sign;
00290   rem_used = ymp_divmodabs(quotient?quotient->digits:NULL, 
00291                            remainder?remainder->digits:NULL, 
00292                            self->digits, other->digits,
00293                            self->used, other->used);
00294   
00295   /*
00296    *  remainder==selfまたはremainder==otherのときにも
00297    *  商のの符号と桁数の調整に影響を与えないように、
00298    *  剰余の符号と桁数は直ぐには書き込まない
00299    */
00300 
00301   if (quotient)
00302     {
00303       /* 商の符号と桁数の調整 */
00304       quotient->sign = self->sign != other->sign;
00305       quotient->used = self->used - other->used + 1;
00306       if (!quotient->digits[quotient->used-1]) --quotient->used;
00307     }
00308 
00309   if (remainder)
00310     {
00311       /* 剰余の符号と桁数を書き込む */
00312       remainder->sign = rem_sign;
00313       remainder->used = rem_used;
00314     }
00315 }
00316 
00317 
00332 digit_t
00333 ymp_divmod_digit(mp_ref_t quotient, mp_cref_t self, digit_t other)
00334 {
00335   digit_t rem; /* 剰余の絶対値 */
00336 
00337   /* 0除算を弾く */
00338   if (other == 0)
00339     {
00340       ymp_fatal("0による除算");
00341       return 0;
00342     }
00343 
00344   /* 被除数が0の場合、商と剰余も0 */
00345   if (self->used == 0)
00346     {
00347       if (quotient) quotient->used = 0;
00348       return 0;
00349     }
00350 
00351   /* 商を格納するのに十分な領域を確保 */
00352   if (quotient) ymp_reserve(quotient, self->used);
00353 
00354   /* 絶対値の除算を行う */
00355   rem = ymp_divmodabs_digit(quotient?quotient->digits:NULL,
00356                             self->digits,
00357                             other,
00358                             self->used);
00359 
00360   /* 桁数と符号の設定 */
00361   if (quotient)
00362     {
00363       if (quotient->digits[quotient->used-1]) --quotient->used;
00364       quotient->sign = self->sign;
00365     }
00366 
00367   if (self->sign && rem)
00368     {
00369       /* 剰余が正になるように調整 */
00370       if (quotient)
00371         {
00372           quotient->used = ymp_addabs(quotient->digits, quotient->digits, 
00373                                       &other, quotient->len, 1);
00374         }
00375       return other - rem;
00376     }
00377   else
00378     {
00379       return rem;
00380     }
00381 }
00382 
00398 int
00399 ymp_div_if_divisible(mp_ref_t quotient, mp_cref_t self, mp_cref_t other)
00400 {
00401   size_t rem_used; /* 剰余の桁数 */
00402   digit_t *quot_buf=NULL, *rem_buf=NULL; /* 商・剰余の一時格納用 */
00403 
00404   /* 0除算を弾く */
00405   if (ymp_is_zero(other))
00406     {
00407       ymp_fatal("0による除算");
00408       return 2;
00409     }
00410 
00411   /* 明らかな場合 */
00412   if (self->used < other->used)
00413     {
00414       if (ymp_is_zero(self))
00415         {
00416           if (quotient) quotient->used = 0;
00417           return 1;
00418         }
00419       else
00420         {
00421           return 0;
00422         }
00423     }
00424 
00425   /* 格納領域を確保 */
00426   if (quotient) YMP_TEMP_ALLOCATE(quot_buf, digit_t, self->used-other->used+1);
00427   YMP_TEMP_ALLOCATE(rem_buf, digit_t, other->used);
00428 
00429   /* 絶対値の除算を実行 */
00430   rem_used = ymp_divmodabs(quot_buf, rem_buf, self->digits, other->digits,
00431                            self->used, other->used);
00432 
00433   /* 剰余が0なら (そのときrem_usedは必ず0) */
00434   if (rem_used==0)
00435     {
00436       if (quotient)
00437         {
00438           /* *quotientに商のデータをコピー */
00439           size_t quot_used;
00440           quotient->sign = self->sign != other->sign;
00441           
00442           quot_used = self->used - other->used + 1;
00443           if (!quot_buf[quot_used-1]) --quot_used;
00444           quotient->used = quot_used;
00445           ymp_reserve(quotient, quot_used);
00446           memcpy(quotient->digits, quot_buf, quot_used);
00447         }
00448       return 1;
00449     }
00450   else
00451     {
00452       return 0;
00453     }
00454 }
00455 
00456 
00457 
00473 int
00474 ymp_div_if_divisible_digit(mp_ref_t quotient, mp_cref_t self, digit_t other)
00475 {
00476   digit_t rem;
00477   digit_t *quot_buf=NULL;
00478 
00479   /* 0除算を弾く */
00480   if (other == 0)
00481     {
00482       ymp_fatal("0による除算");
00483       return 2;
00484     }
00485 
00486   /* 明らかな場合 */
00487   if (ymp_is_zero(self))
00488     {
00489       if (quotient) quotient->used = 0;
00490       return 1;
00491     }
00492 
00493   /* 格納領域を確保 */
00494   if (quotient) YMP_TEMP_ALLOCATE(quot_buf, digit_t, self->used);
00495 
00496   /* 絶対値の除算を実行 */
00497   rem = ymp_divmodabs_digit(quot_buf, self->digits, other, self->used);
00498 
00499   /* 剰余が0なら */
00500   if (rem == 0)
00501     {
00502       if (quotient)
00503         {
00504           /* *quotientに商のデータをコピー */
00505           size_t quot_used;
00506           quotient->sign = self->sign;
00507           
00508           quot_used = self->used;
00509           if (!quot_buf[quot_used-1]) --quot_used;
00510           quotient->used = quot_used;
00511           ymp_reserve(quotient, quot_used);
00512           memcpy(quotient->digits, quot_buf, quot_used);
00513         }
00514       return 1;
00515     }
00516   else
00517     {
00518       return 0;
00519     }
00520 }
00521 

YMPに対してTue Mar 16 19:23:50 2004に生成されました。 doxygen1.2.14 作者 Dimitri van Heesch, © 1997-2002