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

perfect_power.c

解説を見る。
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  * 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 }
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    * 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 }
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;            /* 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 }
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;  /* 下位の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 }
00365 
00366 

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