モジュール | |
下位関数群 | |
関数 | |
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かどうかを判定. より詳しく... |
|
多倍長整数の最小公倍数を計算. Euclid互除法による。
参照 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 } |
|
拡張Euclid互除法を行なう. gcd(a,b) = g = as + btなるg, s, tを算出する.
参照 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 } |
|
剰余環Z/rZ上の逆元. selfのmodulusを法とした乗法逆元を計算する
参照 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 } |
|
孫子(中国)の剰余定理の解を求める. u = u_0 (mod m_0), u = u_1 (mod m_1) なる u を、 m_0 * m_1を法として求める
参照 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 } |
|
|
|
Perfect powerの冪根を求める. <self>が完全pow乗数であればそのpow乗根を<result>に格納 アルゴリズムについては剰余による冪根の高速計算(dvi)を参照
perfect_power.c の 254 行で定義されています。
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 } |
|
Perfect powerかどうかを判定. <self> = n**e なるn, e in N が存在するかどうかを判定。 x アルゴリズムについては剰余による冪根の高速計算(dvi)を参照
perfect_power.c の 321 行で定義されています。
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 } |