00001 #include "multiprec.h"
00002 #include <string.h>
00003
00033 inline static int
00034 ymp_odd_root(mp_ref_t root, mp_cref_t source, size_t pow)
00035 {
00036
00037
00038
00039 size_t clog2, k, two_exp;
00040 struct multiprec g, s, tmp;
00041
00042
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
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
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
00067 ymp_sub(&g, &g, &tmp); ymp_mod_2exp(&g, &g, two_exp);
00068
00069
00070
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
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
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
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 }
00107
00108
00124 inline static int
00125 ymp_nsqrt_mod2exp(mp_ref_t root, mp_cref_t source, size_t e_mod)
00126 {
00127
00128
00129
00130
00131
00132
00133
00134
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
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
00161 ymp_div_2exp(&r, &tmp, 1);
00162 }
00163
00164
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
00172 ymp_div_2exp(root, &tmp, 1);
00173 return 1;
00174 }
00175
00176
00177
00193 inline static int
00194 ymp_odd_sqrt(mp_ref_t root, mp_cref_t source)
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 }
00236
00237
00253 int
00254 ymp_proot(mp_ref_t result, mp_cref_t self, size_t pow)
00255 {
00256 struct multiprec tmp;
00257 size_t n_square;
00258 size_t e2_digits, e2_bits;
00259 register digit_t ld;
00260
00261
00262
00263
00264 if (self->sign || ymp_is_zero(self)) return 0;
00265
00266
00267
00268
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
00280 if ((e2_digits * DIGIT_BIT + e2_bits) % pow != 0) return 0;
00281
00282
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
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 }
00307
00308
00309
00320 int
00321 ymp_is_perfect_power(mp_cref_t self)
00322 {
00323 struct multiprec tmp;
00324 size_t e2_digits, e2_bits, e2;
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
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 }
00365
00366