fibonacci_ppm1.cc

Go to the documentation of this file.
00001 #include "polphi_template.H"
00002 
00009 class Tfibpair
00010 {
00011  private:
00012   mpz_t x1,x2; // (x1,x2) stands for (x1*lambda + x2), which complies with (f[n],f[n-1])
00013   mpz_t h1,h2,h3;
00014 
00015   inline const Tfibpair& operator= (const Tfibpair&) const { MARK; exit(9); return *this; }
00016     // dummy to forbid any implicit inherited use of the assignment operator
00017 
00018  public:
00019   Tfibpair()
00020    {
00021      // Default-Startwert ist lambda^0 = 1 = 0*lambda+1 = (0,1), also f1=F[0]=0, f0=F[-1]=1
00022      mpz_init_set_ui(x1,0);
00023      mpz_init_set_ui(x2,1);
00024      mpz_init(h1); mpz_init(h2); mpz_init(h3);
00025    }
00026   Tfibpair(const unsigned int f1, const unsigned int f0)
00027    {
00028      // Default-Startwert ist lambda^0 = 1 = 0*lambda+1 = (0,1), also f1=F[0]=0, f0=F[-1]=1
00029      // Für den Startwert der Fibonaccifolge wähle man f1=F[1]=1, f0=F[0]=0
00030      mpz_init_set_ui(x1,f1);
00031      mpz_init_set_ui(x2,f0);
00032      mpz_init(h1); mpz_init(h2); mpz_init(h3);
00033    }
00034   Tfibpair(const Tfibpair &X)
00035    {
00036      mpz_init_set(x1,X.x1);
00037      mpz_init_set(x2,X.x2);
00038      mpz_init(h1); mpz_init(h2); mpz_init(h3);
00039    }
00040   ~Tfibpair()
00041    {
00042      mpz_clear(h3); mpz_clear(h2); mpz_clear(h1);
00043      mpz_clear(x2); mpz_clear(x1);
00044    }
00045 
00046   inline void set(const unsigned int f1, const unsigned int f0)
00047    {
00048      mpz_set_ui(x1,f1);
00049      mpz_set_ui(x2,f0);
00050    }
00051   inline void set(const signed int f1, const signed int f0)
00052    {
00053      mpz_set_si(x1,f1);
00054      mpz_set_si(x2,f0);
00055    }
00056   inline void set(const Tfibpair &X)
00057    {
00058      mpz_set(x1,X.x1);
00059      mpz_set(x2,X.x2);
00060      // Hilfsvariablen bleiben unberücksichtigt!
00061    }
00062 
00063 
00064   inline const mpz_t& fn(void) const { return x1; }
00065   inline const mpz_t& fnm1(void) const { return x2; }
00066   inline const mpz_t& Ln(void) { mpz_add(h1,x2,x2); mpz_add(h1,h1,x1); return h1; }
00067 
00068   inline void mod(const mpz_t m)
00069    {
00070      mpz_mod(x1,x1,m);
00071      mpz_mod(x2,x2,m);
00072    }
00073   inline void mul(const Tfibpair &Q)
00074    {
00075      mpz_add(h1,x1,x2); mpz_add(h2,Q.x1,Q.x2); mpz_mul(h1,h1,h2);
00076      mpz_mul(h2,x1,Q.x1); 
00077      mpz_mul(h3,x2,Q.x2); 
00078      mpz_sub(x1,h1,h3); mpz_add(x2,h2,h3);
00079    }
00080   inline void square() 
00081    {
00082      mpz_add(h1,x1,x2); mpz_mul(h1,h1,h1);
00083      mpz_mul(h2,x1,x1); 
00084      mpz_mul(h3,x2,x2); 
00085      mpz_sub(x1,h1,h3); mpz_add(x2,h2,h3);
00086    }
00087   inline void fastsquare()
00088    {
00089      // assumes that first index is already even
00090 #ifdef DEBUG
00091      const bool flag = (mpz_cmp_ui(x1,1)==0 && mpz_cmp_ui(x2,0)==0);
00092      if (flag) cout << "error, error!" << endl;
00093 #endif
00094      mpz_mul(h1,x1,x1); mpz_mul(h2,x2,x2);
00095      mpz_add(x2,h1,h2);
00096      mpz_mul_2exp(h1,h1,2); mpz_sub(h1,h1,h2); mpz_add_ui(h1,h1,2);
00097      mpz_sub(x1,h1,x2);
00098    }
00099   inline void pow(const unsigned int n)
00100    {
00101      // calculating (x1*lambda+x2)^n
00102      Tfibpair Q(*this);
00103      if ((n&1)==0) set(0,1);
00104      for (unsigned int i=2; i<=n; i<<=1)
00105       {
00106         Q.square();
00107         if (n&i) mul(Q);
00108       }
00109    }
00110   inline void powmod(const unsigned int n, const mpz_t m)
00111    {
00112      // standard binary powering algorithm
00113      // this one goes from the lowest bit upwards
00114      Tfibpair Q(*this);
00115      if ((n&1)==0) set(0,1);
00116      for (unsigned int i=2; i<=n; i<<=1)
00117       {
00118         Q.square(); Q.mod(m);
00119         if (n&i) { mul(Q); mod(m); }
00120       }
00121    }
00122 
00123 #if 0
00124   inline void fastpowmod(const unsigned int n, const mpz_t m)
00125    {
00126      // binary powering algorithm, just the other way round:
00127      // this one goes from highest bit downwards.
00128 
00129      // assumes, that
00130      // (1) index of the existing fibonacci number is even, so that
00131      //     assumptions on Lucasvalues are correct
00132      // (2) n is a positive value, so that at least one bit is set
00133 
00134      const Tfibpair saved(*this);
00135      signed int b = 8*sizeof(b)-1; // highest possible bitposition
00136      while ( (n&(1<<b))==0 ) --b; // find highest set bit
00137      while (--b>=0)
00138       {
00139         fastsquare(); mod(m);
00140         if (n&(1<<b)) { mul(saved); mod(m); }
00141       }
00142    }
00143 #else
00144   inline void fastpowmod(const unsigned int n, const mpz_t m)
00145    {
00146      // binary powering algorithm, just the other way round:
00147      // this one goes from highest bit downwards.
00148 
00149      // assumes, that
00150      // (1) index of the existing fibonacci number is even, so that
00151      //     assumptions on Lucasvalues are correct
00152      // (2) n is a positive value, so that at least one bit is set
00153 
00154      mpz_t dx1, dx2;
00155      mpz_init_set(dx1,x1); mpz_init_set(dx2,x2); mpz_add(h3,x1,x2);
00156      signed int b = 8*sizeof(b)-1; // highest possible bitposition
00157      while ( (n&(1<<b))==0 ) --b; // find highest set bit
00158      while (--b>=0)
00159       {
00160         //fastsquare();
00161         mpz_mul(h1,x1,x1); mpz_mul(h2,x2,x2);
00162         mpz_add(x2,h1,h2);
00163         mpz_mul_2exp(h1,h1,2); mpz_sub(h1,h1,h2); mpz_add_ui(h1,h1,2);
00164         mpz_sub(x1,h1,x2);
00165         mod(m);
00166         if (n&(1<<b))
00167          {
00168            //mul(saved);
00169            //mpz_add(h1,x1,x2); already done!
00170            //mpz_add(h2,dx1,dx2); // in h3!
00171            mpz_mul(h1,h1,h3);
00172            mpz_mul(h2,x2,dx2);
00173            mpz_mul(x2,x1,dx1);  
00174            mpz_sub(x1,h1,h2); mpz_add(x2,x2,h2);
00175            mod(m);
00176          }
00177       }
00178      mpz_clear(dx2); mpz_clear(dx1);    
00179    }
00180 #endif
00181 
00182 #if 1
00183   // the following class functions are untested, but they should work:
00184 
00185   inline void set_Fibonacci(const signed int n)
00186    {
00187      if (n==0) { set(0,1); return; }
00188      if (n<0) { set(1,-1); pow(-n); } else { set(1,0); pow(n); }
00189    }
00190 
00191   inline void step_forward(unsigned int d)
00192    {
00193      // (F[n],F[n-1]) -> (F[n+d],F[n+d-1])
00194      // one can also use (F[n+d],F[n+d-1])=(F[n],F[n-1])*(F[d],F[d-1])
00195      // (1) check threshold, whether powering will be worthwhile
00196      // (2) compute (F[d],F[d-1])=lambda^d and multiply...
00197      if (d<100)
00198       {
00199         while(d--) { mpz_swap(x1,x2); mpz_add(x1,x1,x2); }
00200       }
00201      else
00202       {
00203         Tfibpair temp(1,0);
00204         temp.pow(d);
00205         mul(temp); // "bigstep d" ;-)
00206       }
00207    }
00208   inline void step_backward(unsigned int d)
00209    {
00210      // (F[n],F[n-1]) -> (F[n-d],F[n-d-1])
00211      // one can also use (F[n+d],F[n+d-1])=(F[n],F[n-1])*(F[d],F[d-1])
00212      // (1) check threshold, whether powering will be worthwhile
00213      // (2) compute (F[-d],F[-d-1])=lambda^(-d) and multiply...
00214      if (d<100)
00215       {
00216         while(d--) { mpz_sub(x1,x1,x2); mpz_swap(x1,x2); }
00217       }
00218      else
00219       {
00220         Tfibpair temp;
00221         temp.set_Fibonacci(-1); 
00222         temp.pow(d);
00223         mul(temp); // "bigstep -d" ;-)
00224       }
00225    }
00226 #endif
00227 
00228 };
00229 
00230 
00231 class CRingFib
00232 {
00233 private:
00234  Tfibpair a;
00235 
00236   inline const CRingFib& operator= (const CRingFib&) const { MARK; exit(9); return *this; }
00237     // dummy to forbid any implicit inherited use of the assignment operator
00238 
00239 public:
00240  static const std::string name;
00241  static const int SieveIntervalSize=2*3*5*7*11*13*17;
00242  CRingFib() : a() { }
00243  CRingFib(const CRingFib &x) : a(x.a) { }
00244  ~CRingFib() { }
00245  bool set_startvalue(const unsigned int seed=1)
00246   {
00247     a.set(1,0);
00248     return seed==1; // reject seed!=1
00249   }
00250  void set(const CRingFib &x) { a.set(x.a); }
00251  void pow_mod(const unsigned int i, const mpz_t M) { a.powmod(i,M); }
00252  void fast_pow_mod(const unsigned int i, const mpz_t M) { a.fastpowmod(i,M); } // see above
00253  void test_gcd(mpz_t x, const mpz_t M) { mpz_gcd(x,a.fn(),M); }
00254  friend class CRingFibPhase2;
00255 };
00256 const std::string CRingFib::name = "fib";
00257 
00258 
00259 class CRingFibPhase2 : private ForbidAssignment
00260 {
00261 private:
00262  Tfibpair F, stepF, mulF;
00263  mpz_t Fii, Lii, Liip, FD, LD, temp1, temp2;
00264 public:
00265  explicit CRingFibPhase2(const CRingFib &_F) : F(_F.a), stepF(), mulF()
00266   {
00267     F.powmod(2,n); // um wirklich sicherzustellen, dass Index gerade ist...
00268     stepF.set(F), mulF.set(F);
00269     mpz_init(Fii); mpz_init(Lii); mpz_init(Liip);
00270     mpz_init(FD); mpz_init(LD); mpz_init(temp1); mpz_init(temp2);
00271   }
00272  ~CRingFibPhase2()
00273   {
00274     mpz_clear(Fii); mpz_clear(Lii); mpz_clear(Liip);
00275     mpz_clear(FD); mpz_clear(LD); mpz_clear(temp1); mpz_clear(temp2);
00276   }
00277 
00278  void get_polynomdef_point(mpz_t x)
00279   {
00280     mpz_set(x,stepF.fn()); mpz_mul(x,x,x); mpz_mod(x,x,n);
00281   }
00282  void calc_polynomdef_next_point()
00283   {
00284     stepF.mul(mulF); stepF.mod(n);
00285   }
00286 
00287  void calc_EvalStartingPoint(const int D, const double ii)
00288   {
00289     Tfibpair h(F); // only needed temporarily
00290     h.powmod(D,n);
00291     mpz_set(FD,h.fn()); // Fibonacciwert F[D]
00292     mpz_set(LD,h.Ln()); // Lucaswert L[D]
00293 
00294     Tfibpair hp(h);
00295     int pow = static_cast<int>(ii/D);
00296     h.powmod(pow,n);
00297     mpz_set(Fii,h.fn());
00298     mpz_set(Lii,h.Ln());
00299  
00300     if (--pow<0) pow=-pow;
00301     hp.powmod(pow,n);
00302     mpz_set(Liip,hp.Ln()); // Lucaswert L[ii-D]
00303   }
00304 
00305  void get_point_and_calc_next_point(mpz_t x)
00306   {
00307     mpz_mul(x,Fii,Fii); mpz_mod(x,x,n);
00308     // compute values for the next interval...
00309     //ii+=D; // neues Intervall (bis i haben wir nun abgearbeitet)
00310 
00311     // F[ii+D]=(F[ii]*L[D]+F[D]*L[ii])/2
00312     // L[ii+D]=L[ii]*L[D]-L[ii-D]
00313 
00314     mpz_mul(temp1,Fii,LD); mpz_mul(temp2,Lii,FD);
00315     mpz_add(Fii,temp1,temp2); mpz_mod(Fii,Fii,n);
00316     if (mpz_odd_p(Fii)) mpz_add(Fii,Fii,n);
00317     mpz_tdiv_q_2exp(Fii,Fii,1);
00318 
00319     mpz_mul(temp1,Lii,LD); mpz_sub(temp1,temp1,Liip); mpz_mod(Liip,temp1,n);
00320     mpz_swap(Liip,Lii);
00321   }
00322   
00323 };
00324 
00325 
00326 
00327 // explicit instantiation (not necessary)
00328 template void polphi_template<CRingFib,CRingFibPhase2>(const int phase1, const double phase2);
00329 
00330 #define fibonacci_ppm1(phase1,phase2) polphi_template<CRingFib,CRingFibPhase2>(phase1,phase2)

Generated on Wed Nov 7 23:29:25 2007 for Qsieve by  doxygen 1.5.4