basic routines for ContFrac
This commit is contained in:
parent
5544ea4ee7
commit
10985a146b
112
contfrac.cc
112
contfrac.cc
@ -24,12 +24,124 @@
|
|||||||
|
|
||||||
namespace LA {
|
namespace LA {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
ContFrac<T>::ContFrac(double x, const int n, const T thres) : NRVec<T>(n+1)
|
||||||
|
{
|
||||||
|
for(int i=0; i<=n; ++i)
|
||||||
|
{
|
||||||
|
NRVec<T>::v[i]=floor(x);
|
||||||
|
x -= NRVec<T>::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 <typename T>
|
||||||
|
static void cf_helper(ContFrac<T> *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 <typename T>
|
||||||
|
ContFrac<T>::ContFrac(const T p, const T q) : NRVec<T>()
|
||||||
|
{
|
||||||
|
cf_helper<T>(this,p,q,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
ContFrac<T> ContFrac<T>::reciprocal() const
|
||||||
|
{
|
||||||
|
int n=this->length();
|
||||||
|
if((*this)[0] == 0)
|
||||||
|
{
|
||||||
|
ContFrac<T> r(n-1);
|
||||||
|
for(int i=1; i<=n; ++i) r[i-1] = (*this)[i];
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ContFrac<T> r(n+1);
|
||||||
|
r[0]=0;
|
||||||
|
for(int i=0; i<=n; ++i) r[i+1] = (*this)[i];
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void ContFrac<T>::convergent(T *p, T*q, const int trunc) const
|
||||||
|
{
|
||||||
|
int top=this->length();
|
||||||
|
if(trunc != -1) top=trunc;
|
||||||
|
NRVec<T> 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 <typename T>
|
||||||
|
double ContFrac<T>::value(const int trunc) const
|
||||||
|
{
|
||||||
|
T p,q;
|
||||||
|
convergent(&p,&q,trunc);
|
||||||
|
double x=p;
|
||||||
|
x/=q;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void ContFrac<T>::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
|
* forced instantization in the corresponding object file
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
template class ContFrac<int>;
|
template class ContFrac<int>;
|
||||||
template class ContFrac<unsigned int>;
|
template class ContFrac<unsigned int>;
|
||||||
|
template class ContFrac<long>;
|
||||||
|
template class ContFrac<unsigned long>;
|
||||||
|
template class ContFrac<long long>;
|
||||||
|
template class ContFrac<unsigned long long>;
|
||||||
|
|
||||||
|
|
||||||
#define INSTANTIZE(T) \
|
#define INSTANTIZE(T) \
|
||||||
|
|
||||||
|
30
contfrac.h
30
contfrac.h
@ -25,17 +25,45 @@
|
|||||||
|
|
||||||
namespace LA {
|
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 <typename T>
|
||||||
|
class Rational {
|
||||||
|
public:
|
||||||
|
T num;
|
||||||
|
T den;
|
||||||
|
|
||||||
|
Rational(const T p, const T q) : num(p),den(q) {};
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ContFrac : public NRVec<T> {
|
class ContFrac : public NRVec<T> {
|
||||||
|
private:
|
||||||
|
int size() const; //prevent confusion with vector size
|
||||||
public:
|
public:
|
||||||
ContFrac(): NRVec<T>() {};
|
ContFrac(): NRVec<T>() {};
|
||||||
template<int SIZE> ContFrac(const T (&a)[SIZE]) : NRVec<T>(a) {};
|
template<int SIZE> ContFrac(const T (&a)[SIZE]) : NRVec<T>(a) {};
|
||||||
ContFrac(const NRVec<T> &v) : NRVec<T>(v) {}; //allow implicit conversion from NRVec
|
ContFrac(const NRVec<T> &v) : NRVec<T>(v) {}; //allow implicit conversion from NRVec
|
||||||
ContFrac(const int n) : NRVec<T>(n+1) {};
|
ContFrac(const int n) : NRVec<T>(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<T> r) : ContFrac(r.num,r.den) {};
|
||||||
|
|
||||||
|
void canonicalize();
|
||||||
|
void convergent(T *p, T*q, const int trunc= -1) const;
|
||||||
|
Rational<T> rational(const int trunc= -1) const {T p,q; convergent(&p,&q,trunc); return Rational<T>(p,q);};
|
||||||
|
double value(const int trunc= -1) const;
|
||||||
|
ContFrac reciprocal() const;
|
||||||
int length() const {return NRVec<T>::size()-1;};
|
int length() const {return NRVec<T>::size()-1;};
|
||||||
void resize(const int n, const bool preserve=true) {NRVec<T>::resize(n+1,preserve);}
|
void resize(const int n, const bool preserve=true)
|
||||||
|
{
|
||||||
|
int nold=length();
|
||||||
|
NRVec<T>::resize(n+1,preserve);
|
||||||
|
if(preserve) for(int i=nold+1; i<=n;++i) (*this)[i]=0;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,6 +30,8 @@ namespace LA {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class Polynomial : public NRVec<T> {
|
class Polynomial : public NRVec<T> {
|
||||||
|
private:
|
||||||
|
int size() const; //prevent confusion with vector size
|
||||||
public:
|
public:
|
||||||
Polynomial(): NRVec<T>() {};
|
Polynomial(): NRVec<T>() {};
|
||||||
template<int SIZE> Polynomial(const T (&a)[SIZE]) : NRVec<T>(a) {};
|
template<int SIZE> Polynomial(const T (&a)[SIZE]) : NRVec<T>(a) {};
|
||||||
|
37
t.cc
37
t.cc
@ -2172,7 +2172,7 @@ p[0]=p[1]=1;
|
|||||||
CycleIndex<int> c(Sn);
|
CycleIndex<int> c(Sn);
|
||||||
PERM_RANK_TYPE d;
|
PERM_RANK_TYPE d;
|
||||||
Polynomial<int> pp=c.substitute(p,&d);
|
Polynomial<int> 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<p.degree(); ++i) if(d!=pp[i]) laerror("error in cycle index");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(0)
|
if(0)
|
||||||
@ -2414,7 +2414,7 @@ double det = fit.solve();
|
|||||||
cout <<"det= "<<det<<" fit "<<fit<<endl;
|
cout <<"det= "<<det<<" fit "<<fit<<endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(1)
|
if(0)
|
||||||
{
|
{
|
||||||
NRMat<double> m;
|
NRMat<double> m;
|
||||||
cin >>m;
|
cin >>m;
|
||||||
@ -2431,4 +2431,37 @@ NRMat<double> mm=m.permuted_rows(p);
|
|||||||
cout <<mm;
|
cout <<mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(1)
|
||||||
|
{
|
||||||
|
double x;
|
||||||
|
cin >>x;
|
||||||
|
ContFrac<long long> xx(x,20,1000000);
|
||||||
|
cout<<xx;
|
||||||
|
double y=xx.value();
|
||||||
|
cout <<y<<endl;
|
||||||
|
cout << "CF roundoff error = "<<x-y<<endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(0)
|
||||||
|
{
|
||||||
|
int p,q;
|
||||||
|
cin>>p>>q;
|
||||||
|
ContFrac<int> xx(p,q);
|
||||||
|
double z=p; z/=q;
|
||||||
|
ContFrac<int> zz(z,20,100000);
|
||||||
|
ContFrac<int> yy=xx.reciprocal();
|
||||||
|
cout<<xx;
|
||||||
|
cout<<yy;
|
||||||
|
cout<<zz;
|
||||||
|
int pp,qq,rr,ss;
|
||||||
|
xx.convergent(&pp,&qq);
|
||||||
|
yy.convergent(&rr,&ss);
|
||||||
|
cout << pp<<" "<<qq<<endl;
|
||||||
|
cout << rr<<" "<<ss<<endl;
|
||||||
|
if(p!=pp ||q!=qq||qq!=rr||pp!=ss) cout<<"ContFrac error\n";
|
||||||
|
double zzz=zz.value();
|
||||||
|
cout <<z<<" "<<zzz<<endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user