モジュール | |
| 下位関数群 | |
関数 | |
| 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 }
|
1.2.14 作者 Dimitri van Heesch,
© 1997-2002