関数 | |
int | ymp_odd_root (mp_ref_t root, mp_cref_t source, size_t pow) |
正の奇数に対し、完全奇数乗数かどうかを判定. より詳しく... | |
int | ymp_nsqrt_mod2exp (mp_ref_t root, mp_cref_t source, size_t e_mod) |
奇数に対し平方根の逆数を2の冪を法として求める. より詳しく... | |
int | ymp_odd_sqrt (mp_ref_t root, mp_cref_t source) |
奇数に対し平方根を求める. より詳しく... |
|
正の奇数に対し、完全奇数乗数かどうかを判定. <soruce>が完全pow乗数かどうかを判定し、存在すれば冪根を求める。
perfect_power.c の 34 行で定義されています。 参照 multiprec::len, mp_cref_t, multiprec::sign, ymp_abs_clog2, ymp_add, ymp_alloca_initialize, ymp_assign, ymp_assign_2exp, ymp_assign_digit, ymp_compare, ymp_mod_2exp, ymp_modmul_2exp, ymp_modpow_2exp_z, ymp_mul_digit, ymp_pow, と ymp_sub. 呼出 ymp_is_perfect_power, と ymp_proot.
00035 { 00036 /* 00037 * 2-adic Newton iteration. `Modern computer algebra' p.264-268参照 00038 */ 00039 size_t clog2, k, two_exp; 00040 struct multiprec g, s, tmp; 00041 00042 /* clog2 := */ 00043 clog2 = ymp_abs_clog2(source->digits, source->used); 00044 if (clog2 == 0) 00045 { 00046 if (root) ymp_assign_digit(root, 1); 00047 return 1; 00048 } 00049 00050 /* k := 2**{n*k} > <digits> なる最小のk */ 00051 k = clog2 / pow + (clog2 % pow != 0); 00052 00053 ymp_alloca_initialize(&g, k * pow + 1); 00054 ymp_alloca_initialize(&s, source->len + 1); 00055 ymp_alloca_initialize(&tmp, k * pow + 1); 00056 ymp_assign_digit(&g, 1); 00057 ymp_assign_digit(&s, 1); 00058 00059 for (two_exp=2; two_exp<k; two_exp<<=1) 00060 { 00061 /* tmp := f(g_i)s_i = (g_i**pow - source)) * s_i (mod 2**two_exp) */ 00062 ymp_modpow_2exp_z(&tmp, &g, two_exp, pow); 00063 ymp_sub(&tmp, &tmp, source); ymp_mod_2exp(&tmp, &tmp, two_exp); 00064 ymp_modmul_2exp(&tmp, &tmp, &s, two_exp); 00065 00066 /* g_{i+1} := g_i - tmp */ 00067 ymp_sub(&g, &g, &tmp); ymp_mod_2exp(&g, &g, two_exp); 00068 00069 /* tmp := f'(g_{i+1})* s_i**2 00070 * = pow * g_{i+1}**(pow-1) * s_i**2 (mod 2**two_exp) 00071 */ 00072 ymp_modpow_2exp_z(&tmp, &g, two_exp, pow-1); 00073 ymp_mul_digit(&tmp, &tmp, pow); ymp_mod_2exp(&tmp, &tmp, two_exp); 00074 ymp_modmul_2exp(&tmp, &tmp, &s, two_exp); 00075 ymp_modmul_2exp(&tmp, &tmp, &s, two_exp); 00076 00077 /* s_{i+1} := 2*s_i - tmp */ 00078 ymp_add(&s, &s, &s); ymp_mod_2exp(&s, &s, two_exp); 00079 ymp_sub(&s, &s, &tmp); ymp_mod_2exp(&s, &s, two_exp); 00080 } 00081 00082 /* g = g_i - f(g_i)s_i ( mod 2**k )*/ 00083 ymp_modpow_2exp_z(&tmp, &g, k, pow); 00084 ymp_sub(&tmp, &tmp, source); ymp_mod_2exp(&tmp, &tmp, k); 00085 ymp_modmul_2exp(&tmp, &tmp, &s, k); 00086 ymp_sub(&g, &g, &tmp); ymp_mod_2exp(&g, &g, k); 00087 00088 /* if (g < 0) g += 2**k */ 00089 if (g.sign) 00090 { 00091 ymp_assign_2exp(&tmp, k); 00092 ymp_add(&g, &g, &tmp); 00093 } 00094 00095 00096 ymp_pow(&tmp, &g, pow); 00097 if (ymp_compare(&tmp, source) == 0) 00098 { 00099 if (root) ymp_assign(root, &g); 00100 return 1; 00101 } 00102 else 00103 { 00104 return 0; 00105 } 00106 } |
|
奇数に対し平方根の逆数を2の冪を法として求める. もし存在すれば<source> * i**2 = 1 (mod 2**(e_mod+1)) なる自然数iを求める
perfect_power.c の 125 行で定義されています。 参照 DIGIT_BIT, mp_cref_t, ymp_alloca_initialize, ymp_assign_digit, ymp_div_2exp, ymp_modmul_2exp, ymp_neg, と ymp_sub_digit. 呼出 ymp_odd_sqrt.
00126 { 00127 /* 00128 * MATHEMATICS OF COMPUTATION Volume 67, Number 223, 00129 * July 1998, Pages 1253-1283 00130 * 00131 * Daniel J. Bernstein 00132 * "DETECTING PERFECT POWERS IN ESSENTIALLY LINEAR TIME": Section 21 00133 * 00134 * Algorithm S2 and Lemma 21.4 00135 */ 00136 00137 size_t n_digits; 00138 size_t e; 00139 struct multiprec tmp, r; 00140 00141 if ((source->digits[0] & 0x03) != 1) return 0; 00142 if (e_mod == 1) { ymp_assign_digit(root, 1); return 1;} 00143 if ((source->digits[0] & 0x07) != 1) return 0; 00144 if (e_mod == 2) { ymp_assign_digit(root, 1); return 1;} 00145 00146 n_digits = e_mod / DIGIT_BIT + (e_mod % DIGIT_BIT != 0); 00147 ymp_alloca_initialize(&r, n_digits+2); 00148 ymp_alloca_initialize(&tmp, n_digits+2); 00149 00150 ymp_assign_digit(&r, 1); 00151 for (e = 3; e < e_mod; e = 2*e-1) 00152 { 00153 /* tmp := (3r - source*r**3) mod 2**(e+1) */ 00154 ymp_modmul_2exp(&tmp, source, &r, e+1); 00155 ymp_modmul_2exp(&tmp, &tmp, &r, e+1); 00156 ymp_sub_digit(&tmp, &tmp, 3); 00157 ymp_neg(&tmp, &tmp); 00158 ymp_modmul_2exp(&tmp, &tmp, &r, e+1); 00159 00160 /* r := tmp/2 mod 2**e */ 00161 ymp_div_2exp(&r, &tmp, 1); 00162 } 00163 00164 /* tmp := (3r - source*r**3) mod 2**(e_mod+1) */ 00165 ymp_modmul_2exp(&tmp, source, &r, e_mod+1); 00166 ymp_modmul_2exp(&tmp, &tmp, &r, e_mod+1); 00167 ymp_sub_digit(&tmp, &tmp, 3); 00168 ymp_neg(&tmp, &tmp); 00169 ymp_modmul_2exp(&tmp, &tmp, &r, e_mod+1); 00170 00171 /* r := tmp/2 mod 2**e */ 00172 ymp_div_2exp(root, &tmp, 1); 00173 return 1; 00174 } |
|
奇数に対し平方根を求める. もし存在すれば<source> = i**2 なる自然数iを求める
perfect_power.c の 194 行で定義されています。 参照 DIGIT_BIT, MAX, mp_cref_t, multiprec::sign, multiprec::used, ymp_abs_clog2, ymp_add, ymp_alloca_initialize, ymp_assign, ymp_assign_2exp, ymp_compare, ymp_modmul_2exp, ymp_mul, ymp_nsqrt_mod2exp, と ymp_sub. 呼出 ymp_is_perfect_power, と ymp_proot.
00195 { 00196 size_t n_digits, n_bits; 00197 size_t clog2, b; 00198 struct multiprec r, tmp; 00199 00200 clog2 = ymp_abs_clog2(source->digits, source->used); 00201 b = clog2/2 + clog2%2; 00202 00203 n_digits = b / DIGIT_BIT; n_bits = b % DIGIT_BIT; 00204 ymp_alloca_initialize(&r, n_digits + 1); 00205 00206 if (!ymp_nsqrt_mod2exp(&r, source, b)) return 0; 00207 00208 ymp_modmul_2exp(&r, &r, source, b); 00209 00210 ymp_alloca_initialize(&tmp, MAX(2*(n_digits+1), 2*(r.used+1))); 00211 00212 if (r.sign) 00213 { 00214 ymp_assign_2exp(&tmp, b); 00215 ymp_add(&r, &tmp, &r); 00216 } 00217 00218 ymp_mul(&tmp, &r, &r); 00219 if (ymp_compare(source, &tmp) == 0) 00220 { 00221 if (root) ymp_assign(root, &r); 00222 return 1; 00223 } 00224 00225 ymp_assign_2exp(&tmp, b); 00226 ymp_sub(&tmp, &tmp, &r); 00227 ymp_mul(&tmp, &tmp, &tmp); 00228 if (ymp_compare(source, &tmp) == 0) 00229 { 00230 if (root) ymp_assign(root, &r); 00231 return 1; 00232 } 00233 00234 return 0; 00235 } |