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

下位関数群
[算術演算]


関数

size_t ymp_addabs (digit_t *result, const digit_t *lhs, const digit_t *rhs, size_t lhs_len, size_t rhs_len)
 digit_tの列で表されている絶対値の和を求める. より詳しく...

size_t ymp_subabs (digit_t *result, const digit_t *lhs, const digit_t *rhs, size_t lhs_len, size_t rhs_len)
 digit_tの列で表されている絶対値の差を求める. より詳しく...

digit_t ymp_divmodabs_digit (digit_t *quotient, const digit_t *lhs, const digit_t rhs, size_t lhs_len)
 多倍長の自然数をdigit_tで割る. より詳しく...

void do_divmodabs (digit_t *quotient, digit_t *lhs, const digit_t *rhs, size_t lhs_len, size_t rhs_len)
 多倍長自然数の除算の実行. より詳しく...

size_t ymp_divmodabs (digit_t *quotient, digit_t *remainder, const digit_t *lhs, const digit_t *rhs, size_t lhs_len, size_t rhs_len)
 多倍長自然数の除算. より詳しく...

size_t ymp_mulabs (digit_t *result, const digit_t *lhs, const digit_t *rhs, size_t lhs_len, size_t rhs_len)
 digit_tの列で表されている絶対値の積を求める. より詳しく...

size_t ymp_mulabs_digit (digit_t *result, const digit_t *lhs, digit_t rhs, size_t lhs_len)
 digit_tの列で表されている絶対値にdigit_tを掛ける. より詳しく...

size_t ymp_modmulabs (digit_t *result, const digit_t *lhs, const digit_t *rhs, const digit_t *modulus, size_t lhs_len, size_t rhs_len, size_t modulus_len)
 多倍長自然数の積の剰余を求める. より詳しく...

size_t ymp_modmulabs_2exp (digit_t *result, const digit_t *lhs, const digit_t *rhs, size_t pow, size_t lhs_len, size_t rhs_len)
 多倍長自然数の積の、2の冪による剰余を求める. より詳しく...

size_t ymp_modpowabs_z (digit_t *result, const digit_t *source, const digit_t *modulus, size_t source_len, size_t modulus_len, size_t pow)
 多倍長自然数の冪の剰余を求める(冪指数はsize_t). より詳しく...

size_t ymp_modpowabs_2exp_z (digit_t *result, const digit_t *source, size_t len, size_t emod, size_t pow)
 多倍長の自然数の冪の、2の冪による剰余を求める(冪指数はsize_t). より詳しく...

size_t ymp_modpowabs (digit_t *result, const digit_t *source, const digit_t *modulus, const digit_t *pow, size_t source_len, size_t modulus_len, size_t pow_len)
 多倍長自然数の冪の剰余を求める(冪指数は多倍長). より詳しく...

size_t ymp_powabs (digit_t *result, const digit_t *source, size_t source_len, size_t pow)
 多倍長自然数の冪 (冪指数はsize_t). より詳しく...

size_t ymp_modabs_2exp (digit_t *result, const digit_t *self, size_t len, size_t pow)
 多倍長自然数の2の冪乗による剰余. より詳しく...


関数の解説

size_t ymp_addabs digit_t   result,
const digit_t   lhs,
const digit_t   rhs,
size_t    lhs_len,
size_t    rhs_len
[inline]
 

digit_tの列で表されている絶対値の和を求める.

引数:
result  結果を格納する配列の先頭へのポインタ
lhs  第1項を表す配列の先頭へのポインタ
rhs  第2項を表す配列の先頭へのポインタ
lhs_len  lhsのポイントする先の要素数
rhs_len  rhsのポイントする先の要素数
事前条件:
lhs_len >= rhs_len
resultのポイントする先は最大でlhs_len+1要素を格納できること。
覚え書き:
lhs, rhs, resultが一致してもよい
戻り値:
resultに格納された要素数

addsub.c37 行で定義されています。

参照 digit_t, double_digit_t, HIGH_DIGIT, と LOW_DIGIT.

00039 {
00040   double_digit_t tmp = 0;
00041   size_t i;
00042 
00043   for ( i = 0; i < rhs_len; ++i)
00044     {
00045       tmp += lhs[i];
00046       tmp += rhs[i];
00047       result[i] = LOW_DIGIT(tmp);
00048       tmp = HIGH_DIGIT(tmp);
00049     }
00050   for ( ; i < lhs_len; ++i)
00051     {
00052       tmp += lhs[i];
00053       result[i] = LOW_DIGIT(tmp);
00054       tmp = HIGH_DIGIT(tmp);
00055     }
00056   if (LOW_DIGIT(tmp))
00057     {
00058       result[i++] = LOW_DIGIT(tmp);
00059     }
00060   return i;
00061 }

size_t ymp_subabs digit_t   result,
const digit_t   lhs,
const digit_t   rhs,
size_t    lhs_len,
size_t    rhs_len
[inline]
 

digit_tの列で表されている絶対値の差を求める.

引数:
result  結果を格納する配列の先頭へのポインタ
lhs  第1項を表す配列の先頭へのポインタ
rhs  第2項を表す配列の先頭へのポインタ
lhs_len  lhsのポイントする先の要素数
rhs_len  rhsのポイントする先の要素数
事前条件:
(lhsで表される絶対値) >= (rhsで表される絶対値)
resultのポイントする先は最大でlhs_len要素を格納できること。
覚え書き:
lhs, rhs, resultが一致してもよい
戻り値:
resultに格納された要素数

addsub.c81 行で定義されています。

参照 digit_t, double_digit_t, HIGH_DIGIT, LOW_DIGIT, と MULTIPREC_RADIX.

00083 {
00084   double_digit_t tmp = 1;
00085   size_t i;
00086 
00087   for ( i = 0; i < rhs_len; ++i)
00088     {
00089       tmp += MULTIPREC_RADIX - 1;
00090       tmp += lhs[i];
00091       tmp -= rhs[i];
00092       result[i] = LOW_DIGIT(tmp);
00093       tmp = HIGH_DIGIT(tmp);
00094     }
00095   for ( ; i < lhs_len; ++i)
00096     {
00097       tmp += MULTIPREC_RADIX - 1;
00098       tmp += lhs[i];
00099       result[i] = LOW_DIGIT(tmp);
00100       tmp = HIGH_DIGIT(tmp);
00101     }
00102   while (i-- > 0)
00103     {
00104       if (result[i]) break;
00105     }
00106   return ++i;
00107 }

digit_t ymp_divmodabs_digit digit_t   quotient,
const digit_t   lhs,
const digit_t    rhs,
size_t    lhs_len
 

多倍長の自然数をdigit_tで割る.

引数:
quotient  商を格納する配列の先頭へのポインタ NULLならば商は格納されない。
lhs  割られる数を表すdigit_tの列の先頭へのポインタ
rhs  割る数
lhs_len  lhsのポイントする配列の要素数
事前条件:
quotientがNULLでないなら、 そのポイント先は最大でlhs_len個の要素を格納できること
rhsが0でないこと
覚え書き:
quotient, lhsは一致しても良い
戻り値:
剰余
事後条件:
剰余rは 0 <= r < rhs

div.c32 行で定義されています。

参照 digit_t, double_digit_t, LOW_DIGIT, と LOW_DIGIT_TO_HIGH_DIGIT.

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 }

void do_divmodabs digit_t   quotient,
digit_t   lhs,
const digit_t   rhs,
size_t    lhs_len,
size_t    rhs_len
[inline, static]
 

多倍長自然数の除算の実行.

引数:
quotient  商を格納する配列の先頭へのポインタ NULLならば商は格納されない。
lhs  割られる数を表すdigit_tの列の先頭へのポインタ. 終了時には、剰余が格納される
rhs  割る数を表すdigit_tの列の先頭へのポインタ
lhs_len  lhsのポイントする配列の要素数
rhs_len  rhsのポイントする配列の要素数
事前条件:
<rhs>が0でないこと
lhs_len >= rhs_len
quotientがNULLでないなら、 そのポイント先は最大でlhs_len-rhs_len+1個の要素を格納できること
remainderがNULLでないなら、 そのポイント先は最大でrhs_len個の要素を格納できること
quotientはlhs, rhsとは異なること
覚え書き:
<rhs>が0の場合、動作は不定
事後条件:
剰余rは 0 <= r < (rhs)

div.c72 行で定義されています。

参照 DIGIT_HIGHEST_BIT, digit_t, double_digit_t, HIGH_DIGIT, LOW_DIGIT, LOW_DIGIT_TO_HIGH_DIGIT, と MULTIPREC_RADIX.

呼出 ymp_divmodabs.

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 }

size_t ymp_divmodabs digit_t   quotient,
digit_t   remainder,
const digit_t   lhs,
const digit_t   rhs,
size_t    lhs_len,
size_t    rhs_len
 

多倍長自然数の除算.

引数:
quotient  商を格納する配列の先頭へのポインタ NULLならば商は格納されない。
remainder  剰余を格納する配列の先頭へのポインタ NULLならば剰余は格納されない。
lhs  割られる数を表すdigit_tの列の先頭へのポインタ
rhs  割る数を表すdigit_tの列の先頭へのポインタ
lhs_len  lhsのポイントする配列の要素数
rhs_len  rhsのポイントする配列の要素数
事前条件:
<rhs>が0でないこと。0の場合はymp_fatalを呼ぶ。
lhs_used >= rhs_usedであること。そうでない場合は不定
quotientがNULLでないなら、 そのポイント先は最大でlhs_len-rhs_len+1個の要素を格納できること
remainderがNULLでないなら、 そのポイント先は最大でrhs_len個の要素を格納できること
戻り値:
remainderに格納された要素数。 remainderがNULLの場合は0。剰余が0であるときは、戻り値は必ず0
事後条件:
剰余rは 0 <= r < (rhs)
覚え書き:
quotient, remainder, lhs, rhsは一致しても良い

div.c159 行で定義されています。

参照 DIGIT_HIGHEST_BIT, digit_t, do_divmodabs, double_digit_t, HIGH_DIGIT, LOW_DIGIT, LOW_DIGIT_TO_HIGH_DIGIT, ymp_fatal, と YMP_TEMP_ALLOCATE.

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 }

size_t ymp_mulabs digit_t   result,
const digit_t   lhs,
const digit_t   rhs,
size_t    lhs_len,
size_t    rhs_len
[inline]
 

digit_tの列で表されている絶対値の積を求める.

引数:
result  結果を格納する配列の先頭へのポインタ
lhs  第1項を表す配列の先頭へのポインタ
rhs  第2項を表す配列の先頭へのポインタ
lhs_len  lhsのポイントする先の要素数
rhs_len  rhsのポイントする先の要素数
事前条件:
resultのポイントする先は最大で(lhs_len+rhs_len)要素を格納できること。
resultはlhs, rhsとは異なること
覚え書き:
lhs,rhsは一致してもよい
戻り値:
resultに格納された要素数

mul.c31 行で定義されています。

参照 digit_t, double_digit_t, HIGH_DIGIT, と LOW_DIGIT.

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 }

size_t ymp_mulabs_digit digit_t   result,
const digit_t   lhs,
digit_t    rhs,
size_t    lhs_len
[inline]
 

digit_tの列で表されている絶対値にdigit_tを掛ける.

引数:
result  結果を格納する配列の先頭へのポインタ
lhs  掛けられる数を表す配列の先頭へのポインタ
rhs  掛ける数
lhs_len  lhsのポイントする先の要素数
事前条件:
resultのポイントする先は最大でlhs_len+1要素を格納できること。
覚え書き:
lhs, resultが一致してもよい
戻り値:
resultに格納された要素数

mul.c76 行で定義されています。

参照 digit_t, double_digit_t, HIGH_DIGIT, と LOW_DIGIT.

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 }

size_t ymp_modmulabs digit_t   result,
const digit_t   lhs,
const digit_t   rhs,
const digit_t   modulus,
size_t    lhs_len,
size_t    rhs_len,
size_t    modulus_len
[inline]
 

多倍長自然数の積の剰余を求める.

(result) := (lhs) * (rhs) % (modulus) ( ただし、(lhs), (rhs), (modulus)は自然数 )

引数:
result  結果を格納するdigit_tの列の先頭ヘのポインタ
lhs  掛けられる数を表すdigit_tの列の先頭ヘのポインタ
rhs  掛ける数を表すdigit_tの列の先頭ヘのポインタ
modulus  法を表すdigit_tの列の先頭ヘのポインタ
lhs_len  lhsのポイントする領域の要素数
rhs_len  rhsのポイントする領域の要素数
modulus_len  modulusのポイントする領域の要素数
事前条件:
resultのポイントする領域は少なくともmodulus_len個の要素を格納できること
覚え書き:
result, self, other, modulusは一致しても良い
戻り値:
resultに格納された要素数
事後条件:
結果(result)は、0 <= (result) < (modulus)

mul.c120 行で定義されています。

参照 digit_t, ymp_divmodabs, ymp_mulabs, と YMP_TEMP_ALLOCATE.

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 }

size_t ymp_modmulabs_2exp digit_t   result,
const digit_t   lhs,
const digit_t   rhs,
size_t    pow,
size_t    lhs_len,
size_t    rhs_len
[inline]
 

多倍長自然数の積の、2の冪による剰余を求める.

(result) := (lhs) * (rhs) % (2**pow) ( ただし、(lhs), (rhs)は自然数 )

引数:
result  結果を格納するdigit_tの列の先頭ヘのポインタ
lhs  掛けられる数を表すdigit_tの列の先頭ヘのポインタ
rhs  掛ける数を表すdigit_tの列の先頭ヘのポインタ
pow  法の冪指数
lhs_len  lhsのポイントする領域の要素数
rhs_len  rhsのポイントする領域の要素数
事前条件:
resultのポイントする領域は十分な数の要素を格納できること
覚え書き:
resultのポイントする領域は pow / DIGIT_BIT + 1 個を格納できれば十分
result, self, otherは一致しても良い
戻り値:
resultに格納された要素数
事後条件:
結果(result)は、0 <= (result) < (rhs)

mul.c164 行で定義されています。

参照 DIGIT_BIT, digit_t, double_digit_t, HIGH_DIGIT, LOW_DIGIT, と YMP_TEMP_ALLOCATE.

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 }

size_t ymp_modpowabs_z digit_t   result,
const digit_t   source,
const digit_t   modulus,
size_t    source_len,
size_t    modulus_len,
size_t    pow
 

多倍長自然数の冪の剰余を求める(冪指数はsize_t).

<result> := <base>**<pow> % <modulus>

引数:
result  結果を格納するdigit_tの列の先頭へのポインタ
source  底を表すdigit_tの列の先頭へのポインタ
modulus  法を表すdigit_tの列の先頭へのポインタ
source_len  sourceのポイントする領域の長さ(要素数)
modulus_len  modulusのポイントする領域の長さ(要素数)
pow  冪指数
事前条件:
resultはmodulus_len個の要素を格納できること
覚え書き:
result, self, modulusは一致しても良い
戻り値:
resultに格納された要素数
事後条件:
結果<result>は0 <= <result> < <modulus>

mul.c368 行で定義されています。

参照 digit_t, ymp_divmodabs, ymp_modmulabs, と YMP_TEMP_ALLOCATE.

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 }

size_t ymp_modpowabs_2exp_z digit_t   result,
const digit_t   source,
size_t    len,
size_t    emod,
size_t    pow
 

多倍長の自然数の冪の、2の冪による剰余を求める(冪指数はsize_t).

(result) := (source)**(pow) % (2**emod)

引数:
result  結果を格納するdigit_tの列の先頭へのポインタ
source  底を表すdigit_tの列の先頭へのポインタ
len  sourceのポイントする領域の長さ(要素数)
emod  法の冪指数
pow  冪指数
事前条件:
resultは少なくとも emod / DIGIT_BIT + 1 要素を格納できること
覚え書き:
result, sourceは一致しても良い
戻り値:
resultに格納された要素数

mul.c436 行で定義されています。

参照 DIGIT_BIT, digit_t, ymp_modabs_2exp, ymp_modmulabs_2exp, と YMP_TEMP_ALLOCATE.

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 }

size_t ymp_modpowabs digit_t   result,
const digit_t   source,
const digit_t   modulus,
const digit_t   pow,
size_t    source_len,
size_t    modulus_len,
size_t    pow_len
[inline]
 

多倍長自然数の冪の剰余を求める(冪指数は多倍長).

<result> := <self>**<pow> % <modulus>

引数:
result  結果を格納するdigit_tの列の先頭へのポインタ
source  底を表すdigit_tの列の先頭へのポインタ
modulus  法を表すdigit_tの列の先頭へのポインタ
pow  冪指数を表すdigit_tの列の先頭へのポインタ
source_len  sourceのポイントする領域の長さ(要素数)
modulus_len  modulusのポイントする領域の長さ(要素数)
pow_len  powのポイントする領域の長さ(要素数)
事前条件:
resultはmodulus_len個の要素を格納できること
覚え書き:
result, self, modulus, powは一致しても良い
戻り値:
resultに格納された要素数
事後条件:
結果<result>は0 <= <result> < <modulus>

mul.c491 行で定義されています。

参照 DIGIT_HIGHEST_BIT, digit_t, ymp_divmodabs, ymp_modmulabs, と YMP_TEMP_ALLOCATE.

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 }

size_t ymp_powabs digit_t   result,
const digit_t   source,
size_t    source_len,
size_t    pow
[inline]
 

多倍長自然数の冪 (冪指数はsize_t).

<result> := <self>**<pow>

引数:
result  結果を格納するdigit_tの列の先頭へのポインタ
source  底を表すdigit_tの列の先頭へのポインタ
source_len  sourceのポイントする領域の長さ(要素数)
pow  冪指数
事前条件:
resultは source_len * pow 個の要素を格納できること
覚え書き:
result, selfは一致しても良い
戻り値:
resultに格納された要素数

mul.c585 行で定義されています。

参照 digit_t, ymp_mulabs, と YMP_TEMP_ALLOCATE.

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 }

size_t ymp_modabs_2exp digit_t   result,
const digit_t   self,
size_t    len,
size_t    pow
 

多倍長自然数の2の冪乗による剰余.

<self>を2のpow乗で割った剰余をresultに格納する。

引数:
result  剰余を格納するdigit_tの列の先頭へのポインタ
self  元の数を表すdigit_tの列の先頭へのポインタ
len  selfのポイントする領域の長さ(要素数)
pow  冪指数
事前条件:
resultは pow / DIGIT_BIT + (powDIGIT_BIT)?1:0個の要素を格納できること
戻り値:
resultに格納された要素数
覚え書き:
selfとresultは一致してもよい
格納領域の長さは最大でも pow / DIGIT_BIT + 1 あれば十分

shift.c120 行で定義されています。

00121 {
00122   size_t n_digits = pow / DIGIT_BIT;
00123   size_t n_bits = pow % DIGIT_BIT;
00124 
00125   if (n_digits < len)
00126     {
00127       len = n_digits;
00128       if (n_bits)
00129         {
00130           result[n_digits] = self[n_digits] & ( (1u << n_bits) - 1u );
00131           ++n_digits;
00132         }
00133     }
00134   else if (n_digits > len)
00135     {
00136       n_digits = len;
00137     }
00138 
00139   if (result != self) memcpy(result, self, len*sizeof(digit_t));
00140 
00141   while (n_digits-- > 0)
00142     {
00143       if (self[n_digits] != 0) break;
00144     }
00145   return n_digits+1;
00146 }


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