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

mul.c

解説を見る。
00001 #include "multiprec.h"
00002 #include <string.h>
00003 
00030 inline size_t
00031 ymp_mulabs(digit_t *result, const digit_t *lhs, const digit_t *rhs,
00032            size_t lhs_len, size_t rhs_len)
00033 {
00034   double_digit_t tmp=0;
00035   size_t i=0, j=0;
00036 
00037   if (lhs_len == 0 || rhs_len == 0) return 0;
00038   if ((lhs_len==1 && lhs[0]==0) || (rhs_len==1 && rhs[0]==0)) return 0;
00039 
00040   memset(result, 0, (lhs_len+rhs_len)*sizeof(digit_t));
00041   for (i=0; i<lhs_len; ++i)
00042     {
00043       tmp = 0;
00044       for (j=0; j<rhs_len; ++j)
00045         {
00046           tmp += ((double_digit_t)lhs[i]) * rhs[j];
00047           tmp += result[i+j];
00048 
00049           result[i+j] = LOW_DIGIT(tmp);
00050           tmp = HIGH_DIGIT(tmp);
00051         }
00052       result[i+j] = LOW_DIGIT(tmp);
00053     }
00054   if (tmp) ++i;
00055   return i+j-1;
00056 }
00057 
00058 
00059 
00060 
00061 
00075 inline size_t
00076 ymp_mulabs_digit(digit_t *result, 
00077                  const digit_t *lhs, digit_t rhs, size_t lhs_len)
00078 {
00079   double_digit_t tmp = 0, tmp2, tmp3;
00080   size_t i;
00081   for (i=0; i<lhs_len; ++i)
00082     {
00083       tmp2 = ((double_digit_t)lhs[i]) * rhs;
00084       tmp3 = LOW_DIGIT(tmp);
00085       tmp3 += LOW_DIGIT(tmp2);
00086 
00087       result[i] = LOW_DIGIT(tmp3);
00088 
00089       tmp = HIGH_DIGIT(tmp);
00090       tmp += HIGH_DIGIT(tmp2);
00091       tmp += HIGH_DIGIT(tmp3);
00092     }
00093   if (LOW_DIGIT(tmp))
00094     {
00095       result[i] = LOW_DIGIT(tmp);
00096       ++i;
00097     }
00098   return i;
00099 }
00100 
00101 
00119 inline size_t
00120 ymp_modmulabs(digit_t *result, 
00121               const digit_t *lhs, const digit_t *rhs, const digit_t *modulus,
00122               size_t lhs_len, size_t rhs_len, size_t modulus_len)
00123 {
00124   digit_t *product_digits;
00125   size_t product_used;
00126 
00127   YMP_TEMP_ALLOCATE(product_digits, digit_t, lhs_len+rhs_len);
00128 
00129   product_used = ymp_mulabs(product_digits, lhs, rhs, lhs_len, rhs_len);
00130 
00131   if (product_used < modulus_len)
00132     {
00133       memcpy(result, product_digits, sizeof(digit_t)*product_used);
00134       return product_used;
00135     }
00136   else
00137     {
00138       return ymp_divmodabs(NULL, result, product_digits, modulus,
00139                            product_used, modulus_len);
00140     }
00141 }
00142 
00143 
00144 
00163 inline size_t
00164 ymp_modmulabs_2exp(digit_t *result, const digit_t *lhs, const digit_t *rhs, 
00165                    size_t pow, size_t lhs_len, size_t rhs_len)
00166 {
00167   size_t n_digits, n_bits;
00168 
00169   size_t max_len;
00170   digit_t *product;
00171 
00172   double_digit_t tmp;
00173   size_t i, j;
00174 
00175   if (lhs_len == 0 || rhs_len == 0) return 0;
00176   if ((lhs_len==1 && lhs[0]==0) || (rhs_len==1 && rhs[0]==0)) return 0;
00177 
00178 
00179   n_digits = pow / DIGIT_BIT; n_bits = pow % DIGIT_BIT;
00180   max_len = n_digits + (n_bits != 0);
00181   
00182   if (result == lhs || result == rhs)
00183     {
00184       YMP_TEMP_ALLOCATE(product, digit_t, max_len);
00185     }
00186   else
00187     {
00188       product = result;
00189     }
00190 
00191   memset(product, 0, max_len*sizeof(digit_t));
00192 
00193   if (lhs_len > max_len) lhs_len = max_len;
00194   for (i=0; i<lhs_len; ++i)
00195     {
00196       size_t bound = max_len - i;
00197       tmp = 0;
00198       for (j=0; j<rhs_len && j<bound ; ++j)
00199         {
00200           tmp += ((double_digit_t)lhs[i]) * rhs[j];
00201           tmp += product[i+j];
00202 
00203           product[i+j] = LOW_DIGIT(tmp);
00204           tmp = HIGH_DIGIT(tmp);
00205         }
00206       if (i+j < max_len) product[i+j] = LOW_DIGIT(tmp);
00207     }
00208   
00209   if (n_bits) product[n_digits] &= (1u << n_bits)-1;
00210 
00211   while (max_len-- > 0)
00212     {
00213       if (product[max_len]) break;
00214     }
00215   ++max_len;
00216 
00217   if (product != result) memcpy(result, product, max_len * sizeof(digit_t));
00218 
00219   return max_len;
00220 }
00221 
00222 
00236 void
00237 ymp_mul(mp_ref_t result, mp_cref_t self, mp_cref_t other)
00238 {
00239   digit_t *self_digits = self->digits;
00240   digit_t *other_digits = other->digits;
00241   if (result == self)
00242     {
00243       YMP_TEMP_ALLOCATE(self_digits, digit_t, self->used);
00244       memcpy(self_digits, self->digits, sizeof(digit_t)*self->used);
00245     }
00246   if (result == other)
00247     {
00248       YMP_TEMP_ALLOCATE(other_digits, digit_t, self->used);
00249       memcpy(other_digits, other->digits, sizeof(digit_t)*self->used);
00250     }
00251 
00252   ymp_reserve(result, self->used+other->used);
00253   result->used = ymp_mulabs(result->digits, self_digits, other_digits,
00254                             self->used, other->used);
00255 
00256   result->sign = self->sign != other->sign;
00257 }
00258 
00259 
00260 
00274 void
00275 ymp_modmul(mp_ref_t result, mp_cref_t self, mp_cref_t other, mp_cref_t modulus)
00276 {
00277   digit_t *self_digits = self->digits;
00278   digit_t *other_digits = other->digits;
00279 
00280   if (result == self)
00281     {
00282       YMP_TEMP_ALLOCATE(self_digits, digit_t, self->used);
00283       memcpy(self_digits, self->digits, sizeof(digit_t)*self->used);
00284     }
00285   if (result == other)
00286     {
00287       YMP_TEMP_ALLOCATE(other_digits, digit_t, self->used);
00288       memcpy(other_digits, other->digits, sizeof(digit_t)*self->used);
00289     }
00290 
00291   ymp_reserve(result, modulus->used);
00292 
00293   result->used = ymp_modmulabs(result->digits, 
00294                                self_digits, other->digits, modulus->digits,
00295                                self->used, other->used, modulus->used);
00296 
00297   result->sign = self->sign != other->sign;
00298 }
00299 
00300 
00314 void
00315 ymp_modmul_2exp(mp_ref_t result, mp_cref_t self, mp_cref_t other, size_t pow)
00316 {
00317   ymp_reserve(result, pow/DIGIT_BIT + 1);
00318 
00319   result->used = ymp_modmulabs_2exp(result->digits, 
00320                                     self->digits, other->digits,
00321                                     pow, self->used, other->used);
00322 
00323   result->sign = self->sign != other->sign;
00324 }
00325 
00326 
00336 void
00337 ymp_mul_digit(mp_ref_t result, mp_cref_t self, digit_t other)
00338 {
00339   ymp_reserve(result, self->used+1);
00340   result->used = ymp_mulabs_digit(result->digits, 
00341                                   self->digits, other, self->used);
00342   result->sign = self->sign;
00343 }
00344 
00345 
00367 size_t
00368 ymp_modpowabs_z(digit_t *result, const digit_t *source, const digit_t *modulus,
00369                 size_t source_len, size_t modulus_len, size_t pow)
00370 {
00371   /* 繰りかえし2乗法による */
00372 
00373   digit_t *powered_digits; /* self**(2の冪)を保持 */
00374   size_t powered_used;     /* powered_digitsの先に格納された有効要素数 */
00375   size_t result_used;
00376 
00377   /* result == modulus の場合、複製 */
00378   if (result == modulus)
00379     {
00380       digit_t *new_modulus;
00381       YMP_TEMP_ALLOCATE(new_modulus, digit_t, modulus_len);
00382       memcpy(new_modulus, modulus, sizeof(digit_t)*modulus_len);
00383       modulus = new_modulus;
00384     }
00385 
00386   /* <powered> = <self> ** (2**0) */
00387   YMP_TEMP_ALLOCATE(powered_digits, digit_t, modulus_len*2);
00388   if (source_len < modulus_len)
00389     {
00390       powered_used = source_len;
00391       memcpy(powered_digits, source, source_len*sizeof(digit_t));
00392     }
00393   else
00394     {
00395       powered_used = ymp_divmodabs(NULL, powered_digits,
00396                                    source, modulus, source_len, modulus_len);
00397                                
00398     }
00399 
00400   /* <result> = 1 */
00401   result_used = 1; result[0] = 1;
00402 
00403   for (;;)
00404     {
00405       if (pow & 0x01) 
00406         {
00407           result_used = ymp_modmulabs(result, 
00408                                       result, powered_digits, modulus,
00409                                       result_used, powered_used, modulus_len);
00410         }
00411 
00412       pow >>= 1;
00413       if (!pow) return result_used;
00414 
00415       powered_used = ymp_modmulabs(powered_digits, 
00416                                    powered_digits, powered_digits, modulus,
00417                                    powered_used, powered_used, modulus_len);
00418     }
00419 }
00420 
00421 
00435 size_t
00436 ymp_modpowabs_2exp_z(digit_t *result, const digit_t *source,
00437                      size_t len, size_t emod, size_t pow)
00438 {
00439   /* 繰りかえし2乗法による */
00440 
00441   digit_t *powered_digits; /* self**(2の冪)を保持 */
00442   size_t powered_used;     /* powered_digitsの先に格納された有効要素数 */
00443   size_t result_used;      /* resultに格納されている要素数 */
00444   size_t mod_len = emod / DIGIT_BIT + 1;
00445 
00446   /* <powered> = <self> ** (2**0) */
00447   YMP_TEMP_ALLOCATE(powered_digits, digit_t, mod_len);
00448   powered_used = ymp_modabs_2exp(powered_digits, source, len, emod);
00449 
00450   /* <result> = 1 */
00451   result_used = 1; result[0] = 1;
00452 
00453   for (;;)
00454     {
00455       if (pow & 0x01) 
00456         {
00457           result_used = ymp_modmulabs_2exp(result, result, powered_digits,
00458                                            emod, result_used, powered_used);
00459         }
00460 
00461       pow >>= 1;
00462       if (!pow) return result_used;
00463 
00464       powered_used = ymp_modmulabs_2exp(powered_digits, 
00465                                         powered_digits, powered_digits,
00466                                         emod, powered_used, powered_used);
00467     }
00468 }
00469 
00470 
00471 
00490 inline size_t
00491 ymp_modpowabs(digit_t *result, 
00492               const digit_t *source, const digit_t *modulus, 
00493               const digit_t *pow,
00494               size_t source_len, size_t modulus_len, size_t pow_len)
00495 {
00496   /* 繰りかえし2乗法による */
00497 
00498   size_t i;                /* pow->digits[]内のindex */
00499   digit_t bit_mask;        /* pow->digits[i]内のbitテスト用 */
00500 
00501   digit_t *powered_digits; /* self**(2の冪)を保持 */
00502   size_t powered_used;     /* powered_digitsの先に格納された有効要素数 */
00503 
00504   size_t result_used;      /* resultの先に格納された有効要素数 */
00505 
00506   /* result == modulus の場合、複製 */
00507   if (result == modulus)
00508     {
00509       digit_t *new_modulus;
00510       YMP_TEMP_ALLOCATE(new_modulus, digit_t, modulus_len);
00511       memcpy(new_modulus, modulus, sizeof(digit_t)*modulus_len);
00512       modulus = new_modulus;
00513     }
00514 
00515   /* result == pow の場合、複製 */
00516   if (result == pow)
00517     {
00518       digit_t *new_pow;
00519       YMP_TEMP_ALLOCATE(new_pow, digit_t, pow_len);
00520       memcpy(new_pow, pow, sizeof(digit_t)*pow_len);
00521       pow = new_pow;
00522     }
00523 
00524   /* <powered> = <self> ** (2**0) */
00525   YMP_TEMP_ALLOCATE(powered_digits, digit_t, modulus_len*2);
00526   if (source_len < modulus_len)
00527     {
00528       powered_used = source_len;
00529       memcpy(powered_digits, source, sizeof(digit_t)*source_len);
00530     }
00531   else
00532     {
00533       powered_used = ymp_divmodabs(NULL, powered_digits,
00534                                    source, modulus, source_len, modulus_len);
00535                                
00536     }
00537 
00538   /* <result> = 1 */
00539   result_used = 1; result[0] = 1;
00540 
00541   i=0; bit_mask=1;
00542   for (;;)
00543     {
00544       if (pow[i] & bit_mask) 
00545         {
00546           result_used = ymp_modmulabs(result, 
00547                                       result, powered_digits, modulus,
00548                                       result_used, powered_used, modulus_len);
00549         }
00550 
00551       if (bit_mask == DIGIT_HIGHEST_BIT)
00552         { 
00553           bit_mask = 1;
00554           ++i;
00555           if (i==pow_len) return result_used;
00556         }
00557       else
00558         {
00559           bit_mask <<= 1;
00560           if (i==pow_len-1 && pow[i] < bit_mask) return result_used;
00561         }
00562 
00563       powered_used = ymp_modmulabs(powered_digits, 
00564                                    powered_digits, powered_digits, modulus,
00565                                    powered_used, powered_used, modulus_len);
00566     }
00567 }
00568 
00569 
00570 
00584 inline size_t
00585 ymp_powabs(digit_t *result, const digit_t *source, 
00586            size_t source_len, size_t pow) 
00587 {
00588   /* 繰りかえし2乗法による */
00589   digit_t *tmp_digits;     /* 一時的にdigit_t列を待避する為の領域をポイント */
00590   digit_t *powered_digits; /* self**(2の冪)を保持 */
00591   size_t powered_used;     /* powered_digitsの先に格納された有効要素数 */
00592   size_t result_used;
00593 
00594   if (pow == 0)
00595     {
00596       result[0] = 1;
00597       return 1;
00598     }
00599   /* 以下、<result> >= <source>を仮定できる */
00600 
00601 
00602   /* 一時領域を確保 */
00603   YMP_TEMP_ALLOCATE(tmp_digits, digit_t, source_len*pow);
00604 
00605   /* <powered> = <self> ** (2**0) */
00606   YMP_TEMP_ALLOCATE(powered_digits, digit_t, source_len*pow);
00607   powered_used = source_len;
00608   memcpy(powered_digits, source, sizeof(digit_t)*source_len);
00609 
00610   /* <result> = 1 */
00611   result_used = 1; result[0] = 1;
00612 
00613 
00614 
00615   /* 繰りかえし2乗法 */
00616   for (;;)
00617     {
00618       if (pow & 0x01) 
00619         {
00620           memcpy(tmp_digits, result, sizeof(digit_t)*result_used);
00621           result_used = ymp_mulabs(result, tmp_digits, powered_digits,
00622                                     result_used, powered_used);
00623         }
00624 
00625       pow >>= 1;
00626       if (!pow) return result_used;
00627 
00628       memcpy(tmp_digits, powered_digits, sizeof(digit_t)*powered_used);
00629       powered_used = ymp_mulabs(powered_digits, tmp_digits, tmp_digits,
00630                                 powered_used, powered_used);
00631     }
00632 }
00646 void
00647 ymp_pow(mp_ref_t result, mp_cref_t self, size_t pow)
00648 {
00649   /* 結果の格納領域を確保 */
00650   ymp_reserve(result, self->used*MAX(pow, 1));
00651 
00652   result->sign = self->sign && (pow & 0x01);
00653   result->used = ymp_powabs(result->digits, self->digits, self->used, pow);
00654 }
00655 
00669 void
00670 ymp_modpow_z(mp_ref_t result, mp_cref_t self, mp_cref_t modulus, size_t pow)
00671 {
00672   /* 十分な格納領域を確保 */
00673   ymp_reserve(result, modulus->used);
00674 
00675   result->sign = self->sign && (pow & 0x01);
00676   result->used = ymp_modpowabs_z(result->digits, self->digits, modulus->digits,
00677                                  self->used, modulus->used, pow);
00678 }
00679 
00680 
00694 void
00695 ymp_modpow_2exp_z(mp_ref_t result, mp_cref_t self, size_t emod, size_t pow)
00696 {
00697   /* 十分な格納領域を確保 */
00698   ymp_reserve(result, emod / DIGIT_BIT + 1);
00699 
00700   result->sign = self->sign && (pow & 0x01);
00701   result->used = ymp_modpowabs_2exp_z(result->digits, self->digits,
00702                                       self->used, emod, pow);
00703 }
00704 
00705 
00717 void
00718 ymp_modpow(mp_ref_t result, mp_cref_t self, mp_cref_t modulus, mp_cref_t pow)
00719 {
00720   /* 十分な格納領域を確保 */
00721   ymp_reserve(result, modulus->used);
00722 
00723   result->sign = self->sign && (pow->used != 0 || (pow->digits[0] & 0x01));
00724   result->used = ymp_modpowabs(result->digits, 
00725                                self->digits, modulus->digits, pow->digits,
00726                                self->used, modulus->used, pow->used);
00727 }
00728 
00729 

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