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

数論的関数
[多倍長整数]


モジュール

下位関数群

関数

void ymp_euclid (mp_ref_t g, mp_cref_t a, mp_cref_t b)
 多倍長整数の最小公倍数を計算. より詳しく...

void ymp_euclid_ex (mp_ref_t g, mp_ref_t s, mp_ref_t t, mp_cref_t a, mp_cref_t b)
 拡張Euclid互除法を行なう. より詳しく...

int ymp_modinv (mp_ref_t result, mp_cref_t self, mp_cref_t modulus)
 剰余環Z/rZ上の逆元. より詳しく...

int ymp_binary_sunzi (mp_ref_t result, const mp_cref_t remainders[2], const mp_cref_t moduli[2])
 孫子(中国)の剰余定理の解を求める. より詳しく...

void ymp_multi_euclid (mp_ref_t result, size_t len, const struct multiprec *ary)
int ymp_proot (mp_ref_t result, mp_cref_t self, size_t pow)
 Perfect powerの冪根を求める. より詳しく...

int ymp_is_perfect_power (mp_cref_t self)
 Perfect powerかどうかを判定. より詳しく...


関数の解説

void ymp_euclid mp_ref_t    g,
mp_cref_t    a,
mp_cref_t    b
 

多倍長整数の最小公倍数を計算.

Euclid互除法による。

引数:
g  結果を格納されるstruct multiprecへのポインタ
a  第1項を表すstruct multiprecへのポインタ
b  第2項を表すstruct multiprecへのポインタ
事後条件:
求められた最小公倍数は非負

euclid.c22 行で定義されています。

参照 digit_t, multiprec::digits, mp_cref_t, multiprec::used, ymp_assign_array, ymp_divmodabs, と YMP_TEMP_ALLOCATE.

00023 {
00024   struct {
00025     size_t used;
00026     digit_t *digits;
00027   } r0, r1;
00028 
00029   r0.used = a->used; r1.used = b->used;
00030   YMP_TEMP_ALLOCATE(r0.digits, digit_t, r0.used);
00031   YMP_TEMP_ALLOCATE(r1.digits, digit_t, r1.used);
00032   memcpy(r0.digits, a->digits, r0.used*sizeof(digit_t));
00033   memcpy(r1.digits, b->digits, r1.used*sizeof(digit_t));
00034 
00035   while (r1.used !=0 && (r1.used != 1 || r1.digits[0] != 0))
00036     {
00037       register size_t tmp_used;
00038       register digit_t *tmp_digits;
00039       if (r0.used >= r1.used)
00040         {
00041           r0.used = ymp_divmodabs(NULL, r0.digits, 
00042                                   r0.digits, r1.digits, r0.used, r1.used);
00043         }
00044       tmp_used = r0.used; r0.used = r1.used; r1.used = tmp_used;
00045       tmp_digits = r0.digits; r0.digits = r1.digits; r1.digits = tmp_digits;
00046     }
00047   ymp_assign_array(g, r0.used, r0.digits);
00048 }

void ymp_euclid_ex mp_ref_t    g,
mp_ref_t    s,
mp_ref_t    t,
mp_cref_t    a,
mp_cref_t    b
 

拡張Euclid互除法を行なう.

gcd(a,b) = g = as + btなるg, s, tを算出する.

引数:
g  結果を格納されるstruct multiprecへのポインタ 不用なときはNULLを指定する
s  結果を格納されるstruct multiprecへのポインタ 不用なときはNULLを指定する
t  結果を格納されるstruct multiprecへのポインタ 不用なときはNULLを指定する
a  第1項を表すstruct multiprecへのポインタ
b  第2項を表すstruct multiprecへのポインタ
覚え書き:
g, s, tの符号は不定
勿論、(s,t)=1

euclid.c68 行で定義されています。

参照 MAX, mp_cref_t, multiprec::used, ymp_alloca_initialize, ymp_assign, ymp_destroy, ymp_divmod, ymp_initialize, ymp_initialize_by_digit, ymp_is_zero, ymp_mul, ymp_sub, と ymp_swap.

00069 {
00070   struct multiprec r0, r1, s0, s1, t0, t1, q, tmp;
00071 
00072   ymp_alloca_initialize(&r0, a->used);
00073   ymp_alloca_initialize(&r1, b->used);
00074   ymp_alloca_initialize(&q, MAX(a->used, b->used));
00075   ymp_assign(&r0, a); ymp_assign(&r1, b);
00076   
00077   ymp_initialize_by_digit(&s0, 1); ymp_initialize_by_digit(&s1, 0);
00078   ymp_initialize_by_digit(&t0, 0); ymp_initialize_by_digit(&t1, 1);
00079   ymp_initialize(&tmp);
00080 
00081   while (!ymp_is_zero(&r1))
00082     {
00083       ymp_divmod(&q, &r0, &r0, &r1);
00084       ymp_mul(&tmp, &q, &s1);
00085       ymp_sub(&s0, &s0, &tmp);
00086       ymp_mul(&tmp, &q, &t1);
00087       ymp_sub(&t0, &t0, &tmp);
00088 
00089       ymp_swap(&r0, &r1);
00090       ymp_swap(&s0, &s1);
00091       ymp_swap(&t0, &t1);
00092     }
00093 
00094   if (g) ymp_assign(g, &r0);
00095   if (s) ymp_assign(s, &s0);
00096   if (t) ymp_assign(t, &t0);
00097   ymp_destroy(&s0); ymp_destroy(&s1);
00098   ymp_destroy(&t0); ymp_destroy(&t1);
00099   ymp_destroy(&tmp);
00100 }

int ymp_modinv mp_ref_t    result,
mp_cref_t    self,
mp_cref_t    modulus
 

剰余環Z/rZ上の逆元.

selfのmodulusを法とした乗法逆元を計算する

引数:
result  結果を格納されるstruct multiprecへのポインタ
self  元の数を表すstruct multiprecへのポインタ
modulus  法を表すstruct multiprecへのポインタ
戻り値:
0  逆元が正しく計算された
1  gcd(self, modulus)が1でなかったために、正しく計算されなかった

euclid.c114 行で定義されています。

参照 multiprec::digits, MAX, mp_cref_t, multiprec::sign, multiprec::used, ymp_alloca_initialize, ymp_assign, ymp_assign_digit, ymp_divmod, ymp_is_zero, ymp_mod, ymp_mul, ymp_sub, と ymp_swap.

00115 {
00116   struct multiprec r0, r1, s0, s1, q, tmp;
00117   register size_t len = MAX(self->used, modulus->used);
00118 
00119   ymp_alloca_initialize(&r0, self->used);          /* |r0| <= |self|        */
00120   ymp_alloca_initialize(&r1, modulus->used);       /* |r1| <= |modulus|     */
00121   ymp_alloca_initialize(&s0, modulus->used+len+1); /* |s0| <= |r0|*|q|+|s1| */
00122   ymp_alloca_initialize(&s1, modulus->used+len+1); /* |s1| <= |r1|*|q|+|s0| */
00123   ymp_alloca_initialize(&q, len);                  /* |q|  <= max(|r0|,|r1|)*/
00124   ymp_alloca_initialize(&tmp, modulus->used+len);  /* |tmp| <= |r_i|*|q|    */
00125 
00126   ymp_assign(&r0, self); ymp_assign(&r1, modulus);
00127   ymp_assign_digit(&s0, 1); ymp_assign_digit(&s1, 0);
00128 
00129   while (!ymp_is_zero(&r1))
00130     {
00131       ymp_divmod(&q, &r0, &r0, &r1);
00132       ymp_mul(&tmp, &s1, &q);
00133       ymp_sub(&s0, &s0, &tmp);
00134       ymp_mod(&s0, &s0, modulus);
00135 
00136       ymp_swap(&r0, &r1);
00137       ymp_swap(&s0, &s1);
00138     }
00139   
00140   if (r0.used == 1 && r0.digits[0] == 1)
00141     {
00142       ymp_assign(result, &s0);
00143       if (r0.sign) result->sign = !result->sign;
00144       return 0;
00145     }
00146   else
00147     {
00148       return 1;
00149     }
00150 }

int ymp_binary_sunzi mp_ref_t    result,
const mp_cref_t    remainders[2],
const mp_cref_t    moduli[2]
 

孫子(中国)の剰余定理の解を求める.

u = u_0 (mod m_0), u = u_1 (mod m_1) なる u を、 m_0 * m_1を法として求める

引数:
result  結果uを格納するstruct multiprecへのポインタ
remainders  u_0, u_1をそれぞれ表すstruct multiprecへのポインタの配列
moduli  m_0, m_1をそれぞれ表すstruct multiprecへのポインタの配列
事前条件:
<m_0>と<m_1>は互いに素であること。そうでない場合、結果は正しくない
戻り値:
0  正しく計算された
1  <m_0>と<m_1>は互いに素でないので正しく計算されなかった

euclid.c166 行で定義されています。

参照 MAX, mp_cref_t, ymp_add, ymp_alloca_initialize, ymp_mod, ymp_modinv, ymp_modmul, ymp_mul, と ymp_sub.

00168 {
00169   /*
00170    * H. L. Garnerの高速解法
00171    * c_{0,1} := m_0^{-1} (mod m_1)
00172    *
00173    * v_0 := u_0 mod m_0
00174    * v_1 := (u_1 - u_0) * c_{0,1} mod m_1
00175    *
00176    * u = v_1 * m_0 + v_0
00177    */
00178 
00179   struct multiprec m_0_inv; /* m_0^{-1} (mod m_1) */
00180   struct multiprec v[2];
00181   register size_t len;
00182 
00183   ymp_alloca_initialize(&m_0_inv, moduli[1]->used);
00184   if (ymp_modinv(&m_0_inv, moduli[0], moduli[1])) return 1;
00185 
00186   ymp_alloca_initialize(&v[0], moduli[0]->used);
00187   ymp_mod(&v[0], remainders[0], moduli[0]);
00188 
00189   len = MAX(remainders[1]->used, moduli[0]->used + moduli[1]->used);
00190   ymp_alloca_initialize(&v[1], len);
00191 
00192   ymp_sub(&v[1], remainders[1], &v[0]);
00193   ymp_modmul(&v[1], &v[1], &m_0_inv, moduli[1]);
00194   ymp_mul(&v[1], &v[1], moduli[0]);
00195 
00196   ymp_add(result, &v[1], &v[0]);
00197   return 0;
00198 }

void ymp_multi_euclid mp_ref_t    result,
size_t    len,
const struct multiprec   ary
 

int ymp_proot mp_ref_t    result,
mp_cref_t    self,
size_t    pow
 

Perfect powerの冪根を求める.

<self>が完全pow乗数であればそのpow乗根を<result>に格納

アルゴリズムについては剰余による冪根の高速計算(dvi)を参照

引数:
result  冪根を格納するstruct multiprecへのポインタ
self  対象の整数を表すstruct multiprecへのポインタ
pow  冪指数
戻り値:
<self>が完全pow乗数であれば非0。そうでなければ0
事後条件:
<self>がpow乗数でなければ<result>は変化しない。

perfect_power.c254 行で定義されています。

00255 {
00256   struct multiprec tmp;
00257   size_t n_square;            /* powの素因数分解の中の2の個数 */
00258   size_t e2_digits, e2_bits;  /* 下位の0の並んだ部分の、digit数, bit数 */
00259   register digit_t ld;
00260 
00261 
00262 
00263   /* 正数以外は除く */
00264   if (self->sign || ymp_is_zero(self)) return 0;
00265 
00266 
00267 
00268   /* e2 := {2**e が <self> を割る最大の e} */
00269   for (e2_digits=0; e2_digits<self->used; ++e2_digits)
00270     {
00271       if (self->digits[e2_digits] != 0) break;
00272     }
00273   e2_bits = 0;
00274   for (ld = self->digits[e2_digits]; (ld & 0x1) == 0; ld>>=1)
00275     {
00276       ++e2_bits;
00277     }
00278 
00279   /* 素因数分解の中の2の冪指数をチェック */
00280   if ((e2_digits * DIGIT_BIT + e2_bits) % pow != 0) return 0;
00281 
00282   /* 以下、2の冪は考えなくて良い */
00283 
00284 
00285   n_square = 0;
00286   while ( (pow & 0x01) == 0 ) { pow >>= 1; ++n_square; }
00287 
00288 
00289   ymp_alloca_initialize(&tmp, self->used - e2_digits);
00290 
00291   ymp_div_2exp(&tmp, self, e2_digits * DIGIT_BIT + e2_bits);
00292   if (!ymp_odd_root(&tmp, &tmp, pow))
00293     {
00294       return 0;
00295     }
00296 
00297 
00298   /* 以下、冪指数のうち2冪の部分のみ調べる */
00299   while (n_square-- > 0)
00300     {
00301       if (!ymp_odd_sqrt(&tmp, &tmp)) return 0;
00302     }
00303   
00304   ymp_assign(result, &tmp);
00305   return 1;
00306 }

int ymp_is_perfect_power mp_cref_t    self
 

Perfect powerかどうかを判定.

<self> = n**e なるn, e in N が存在するかどうかを判定。 x アルゴリズムについては剰余による冪根の高速計算(dvi)を参照

引数:
self  対象の整数を表すstruct multiprecへのポインタ
戻り値:
<self>がperfect powerであれば非0。そうでなければ0

perfect_power.c321 行で定義されています。

00322 {
00323   struct multiprec tmp;
00324   size_t e2_digits, e2_bits, e2;  /* 下位の0の並んだ部分の、digit数, bit数 */
00325   size_t pow1, pow2, max_pow;
00326   register digit_t ld;
00327 
00328   /* 正数以外は除く */
00329   if (self->sign || ymp_is_zero(self)) return 0;
00330 
00331   /* e2 := {2**e が <self> を割る最大の e} */
00332   for (e2_digits=0; e2_digits<self->used; ++e2_digits)
00333     {
00334       if (self->digits[e2_digits] != 0) break;
00335     }
00336   e2_bits = 0;
00337   for (ld = self->digits[e2_digits]; (ld & 0x1) == 0; ld>>=1)
00338     {
00339       ++e2_bits;
00340     }
00341   e2 = e2_digits * DIGIT_BIT + e2_bits;
00342 
00343   
00344   ymp_alloca_initialize(&tmp, self->used - e2_digits);
00345   ymp_div_2exp(&tmp, self, e2);
00346   
00347   /* 完全平方か? */
00348   if (e2 % 2 == 0 && ymp_odd_sqrt(NULL, &tmp)) return 1;
00349 
00350   /* 完全立方か? */
00351   if (e2 % 3 == 0 && ymp_odd_root(NULL, &tmp, 3)) return 1;
00352 
00353   /* 完全奇素数乗か ? */
00354   max_pow = ymp_abs_clog2(tmp.digits, tmp.used);
00355   for (pow1=1, pow2=5; 1; pow1 += 6, pow2 += 6)
00356     {
00357       if (pow1 > max_pow) break;
00358       if (e2 % pow1 == 0 && ymp_odd_root(NULL, &tmp, pow1)) return 1;
00359       if (pow2 > max_pow) break;
00360       if (e2 % pow2 == 0 && ymp_odd_root(NULL, &tmp, pow2)) return 1;
00361     }
00362 
00363   return 0;
00364 }


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