#include #include #include #include #include #include #include #include #include #include #include #include "lodepng.h" using namespace std; using i64 = int64_t; const double EPSILON=1e-8; i64 ipow(i64 b,i64 e){ assert(e>=0); if(e==0)return 1; if(e==1)return b; i64 x=1; while(e!=0){ if(e&1)x*=b; b*=b; e>>=1; } return x; } int ilog(i64 n){ assert(n!=0); int l=0; while(n>>=1)l++; return l; } class Polynomial; ostream& operator<<(ostream &os,const Polynomial &poly); class Polynomial : public vector { public: Polynomial() = default; Polynomial(size_t sz):vector(sz){} Polynomial(initializer_list init):vector(init){} Polynomial d() const { Polynomial res(size()-1); for(size_t i=1;i0); return size()-1; } // Returns quotient, *this becomes remainder Polynomial div(const Polynomial &p){ // cerr<<*this<<" / "<0); Polynomial quo(size()-p.size()+1); for(ssize_t i=size()-p.size();i>=0;i--){ double q=operator[](i+p.size()-1)/p.back(); quo[i]=q; for(size_t j=0;j1&&abs(back())0)==(poly.ev(R)>0)){ L-=20; R+=20; } double M=(L+R)/2; for(int i=0;i0)==(poly.ev(L)>0))L=M; else R=M; } return M; } double newton(const Polynomial &poly){ assert(poly.odd()); Polynomial deriv=poly.d(); double x=0,xn; do { double d=deriv.ev(x); while(d==0){ x+=0.01; d=deriv.ev(x); } xn=x-poly.ev(x)/d; } while(xn-x>EPSILON); return xn; } pair bairstow(const Polynomial &poly){ assert(poly.even()&&poly.degree()>=2); const size_t n=poly.degree(); double u=poly[n-1]/poly[n],v=poly[n-2]/poly[n]; if(abs(u)=0;i--){ barr[i]=poly[i+2]-u*barr[i+1]-v*barr[i+2]; farr[i]=barr[i+2]-u*farr[i+1]-v*farr[i+2]; } double c=poly[1]-u*barr[0]-v*barr[1]; double d=poly[0]-v*barr[0]; double g=barr[1]-u*farr[0]-v*farr[1]; double h=barr[0]-v*farr[1]; double discr=1/(v*g*g+h*(h-u*g)); // cerr<<"u="< quadratic(double u,double v){ double D=u*u-4*v; if(D>=0){ double sqrtD2=sqrt(D)/2; return {{-u/2+sqrtD2,0},{-u/2-sqrtD2,0}}; } else { double sqrtD2=sqrt(-D)/2; return {{-u/2,sqrtD2},{-u/2,-sqrtD2}}; } } vector allroots(const Polynomial &poly){ assert(poly.degree()>=1); if(poly.degree()==1){ return {{-(double)poly[0]/poly[1],0}}; } if(poly.odd()){ double rt=bisect(poly,30); vector r=allroots(Polynomial(poly).div({-rt,1})); r.push_back({rt,0}); return r; } pair quadr=bairstow(poly); vector r=poly.degree()==2 ? vector() : allroots(Polynomial(poly).div({quadr.second,quadr.first,1})); pair rts=quadratic(quadr.first,quadr.second); r.push_back(rts.first); r.push_back(rts.second); return r; } } void check(const Com &c){ assert(!::isnan(c.r)&&!::isnan(c.i)); } void check(const vector &v){ for(const Com &c : v)check(c); } namespace Gens { class Generator{ public: virtual Polynomial get(i64 n) const = 0; virtual i64 total() const = 0; }; template class Christensen : public Generator{ public: Polynomial get(i64 n) const { int d=1; while(d<=D){ i64 p=ipow(2*N+1,d); if(nD)return {}; Polynomial poly(d+1); for(int dd=0;dd class Derbyshire : public Generator{ public: Polynomial get(i64 n) const { n+=2; const int d=ilog(n); if(d>D)return {}; Polynomial poly(d+1); for(int dd=0;dd readData(const char *fname){ ifstream f(fname); assert(f); int width,height; f>>width>>height; assert(width>0&&width<10000&&height>0&&height<10000); int *tally=new int[width*height]; for(int i=0;i>tally[i]; } return make_tuple(tally,width,height); } inline double interpCurve(double x){ // return atan(30*x); return pow(x,1.0/2); // return sqrt(log(18*pow(x,0.7)+1)); // return x; } inline double interp(double x,double clip){ return min(interpCurve(x)/interpCurve(clip),1.0); } void buildImage(unsigned char *image,const int *tally,int width,int height){ int maxval=0; for(int i=0;i r=FR::allroots(poly); for(const Com &c : r){ int x=(c.r-S.minx)/(S.maxx-S.minx)*S.width; int y=(c.i-S.miny)/(S.maxy-S.miny)*S.height; if(x<0||x>=S.width||y<0||y>=S.height)continue; tally[S.width*y+x]++; } } } int main(int argc,char **argv){ int *tally; Settings S={ .minx=0,.maxx=1.5, .miny=0,.maxy=1.5, .width=2000,.height=0 }; S.height=S.width/(S.maxx-S.minx)*(S.maxy-S.miny); // const double minx=-3,maxx=3,miny=-3,maxy=3; if(argc==1){ // Gens::Christensen<4,5> gen; Gens::Derbyshire<20> gen; i64 ntotal=gen.total(); int ncores=thread::hardware_concurrency(); cerr<<"Factoring "<