diff --git a/contfrac.cc b/contfrac.cc index 70aaf27..6c7eed1 100644 --- a/contfrac.cc +++ b/contfrac.cc @@ -24,12 +24,124 @@ namespace LA { +template +ContFrac::ContFrac(double x, const int n, const T thres) : NRVec(n+1) +{ +for(int i=0; i<=n; ++i) + { + NRVec::v[i]=floor(x); + x -= NRVec::v[i]; + double y= 1./x; + if(x==0. || (thres && fabs(y)>thres)) {resize(i,true); return;} + x=y; + } +} + + +//we have to recursively first determine length and then allocate and fill the values during recursion unwinding +template +static void cf_helper(ContFrac *me, T p, T q, int level) +{ +T div=p/q; +{ +T rem=p%q; +if(rem) cf_helper(me,q,rem,level+1); +else me->resize(level); +} +(*me)[level]=div; +} + +template +ContFrac::ContFrac(const T p, const T q) : NRVec() +{ +cf_helper(this,p,q,0); +} + + +template +ContFrac ContFrac::reciprocal() const +{ +int n=this->length(); +if((*this)[0] == 0) + { + ContFrac r(n-1); + for(int i=1; i<=n; ++i) r[i-1] = (*this)[i]; + return r; + } +else + { + ContFrac r(n+1); + r[0]=0; + for(int i=0; i<=n; ++i) r[i+1] = (*this)[i]; + return r; + } +} + + +template +void ContFrac::convergent(T *p, T*q, const int trunc) const +{ +int top=this->length(); +if(trunc != -1) top=trunc; +NRVec hh(top+3),kk(top+3); +T *h= &hh[2]; +T *k= &kk[2]; +//start for recurrent relations +h[-2]=k[-1]=0; +h[-1]=k[-2]=1; +for(int i=0; i<=top; ++i) + { + if(i>0 && (*this)[i]==0) //terminate by 0 which means infinity if not canonically shortened + { + *p=h[i-1]; + *q=k[i-1]; + return; + } + h[i] = (*this)[i]*h[i-1] + h[i-2]; + k[i] = (*this)[i]*k[i-1] + k[i-2]; + } +*p=h[top]; +*q=k[top]; +} + +template +double ContFrac::value(const int trunc) const +{ +T p,q; +convergent(&p,&q,trunc); +double x=p; +x/=q; +return x; +} + + +template +void ContFrac::canonicalize() +{ +int n=this->length(); +if(n==0) return; +if((*this)[n]==1) {(*this)[n]=0; ++(*this)[n-1];} //avoid deepest 1/1 +for(int i=1; i<=n; ++i) //truncate if possible + { + if((*this)[i]==0) //convention for infinity + { + resize(i-1,true); + return; + } + } +} + /***************************************************************************//** * forced instantization in the corresponding object file ******************************************************************************/ template class ContFrac; template class ContFrac; +template class ContFrac; +template class ContFrac; +template class ContFrac; +template class ContFrac; + #define INSTANTIZE(T) \ diff --git a/contfrac.h b/contfrac.h index 8e5731c..c870b5b 100644 --- a/contfrac.h +++ b/contfrac.h @@ -25,17 +25,45 @@ namespace LA { +//simple finite continued fraction class +//NOTE: 0 on any position >0 means actually infinity; simplify() shortens the vector +//presently implements just conversion to/from rationals and floats +//maybe implement arithmetic by Gosper's method cf. https://perl.plover.com/classes/cftalk/TALK + +template +class Rational { +public: + T num; + T den; + + Rational(const T p, const T q) : num(p),den(q) {}; +}; template class ContFrac : public NRVec { +private: + int size() const; //prevent confusion with vector size public: ContFrac(): NRVec() {}; template ContFrac(const T (&a)[SIZE]) : NRVec(a) {}; ContFrac(const NRVec &v) : NRVec(v) {}; //allow implicit conversion from NRVec ContFrac(const int n) : NRVec(n+1) {}; + ContFrac(double x, const int n, const T thres=0); //might yield a non-canonical form + ContFrac(const T p, const T q); //should yield a canonical form + ContFrac(const Rational r) : ContFrac(r.num,r.den) {}; + void canonicalize(); + void convergent(T *p, T*q, const int trunc= -1) const; + Rational rational(const int trunc= -1) const {T p,q; convergent(&p,&q,trunc); return Rational(p,q);}; + double value(const int trunc= -1) const; + ContFrac reciprocal() const; int length() const {return NRVec::size()-1;}; - void resize(const int n, const bool preserve=true) {NRVec::resize(n+1,preserve);} + void resize(const int n, const bool preserve=true) + { + int nold=length(); + NRVec::resize(n+1,preserve); + if(preserve) for(int i=nold+1; i<=n;++i) (*this)[i]=0; + } }; diff --git a/polynomial.h b/polynomial.h index f7f41f8..f4b21ea 100644 --- a/polynomial.h +++ b/polynomial.h @@ -30,6 +30,8 @@ namespace LA { template class Polynomial : public NRVec { +private: + int size() const; //prevent confusion with vector size public: Polynomial(): NRVec() {}; template Polynomial(const T (&a)[SIZE]) : NRVec(a) {}; diff --git a/t.cc b/t.cc index da887d2..fc48b46 100644 --- a/t.cc +++ b/t.cc @@ -2172,7 +2172,7 @@ p[0]=p[1]=1; CycleIndex c(Sn); PERM_RANK_TYPE d; Polynomial pp=c.substitute(p,&d); -for(int i=0; i<=p.size(); ++i) if(d!=pp[i]) laerror("error in cycle index"); +for(int i=0; i m; cin >>m; @@ -2431,4 +2431,37 @@ NRMat mm=m.permuted_rows(p); cout <>x; +ContFrac xx(x,20,1000000); +cout<