/* Generated by the Cosmo Code Visual Builder, Version 2.3. */ import java.awt.*; import java.applet.*; import Complex; //since Complex numbers are not part of the Java 1.1 standard libraries. //I used Alexander Anderson's fine class http://www.netlib.no/netlib/java/ (see //http://www.almide.demon.co.uk/html/Complex/Complex_for_Java.html ) //except the complicated path ORG/... the file is unchanged //{{ import_classes - Begin Non-Editable Code Block //}} import_classes - End Non-Editable Code Block /** * Put the class description here. * @author Raymond Manzoni * @version 0.7 (29 oct 02) **/ public class critical extends java.awt.Canvas { //public DecimalFormat dF; /** * Initialize this object. **/ public critical() { //{{ init_applet - Begin Non-Editable Code Block setSize(680, 523); //}} init_applet - End Non-Editable Code Block //{{ init_objects - Begin Non-Editable Code Block //}} init_objects - End Non-Editable Code Block //Format init //dF = DecimalFormat.getNumberInstance(); //dF.format( } /*============================================================* * Mathematical Part * *============================================================*/ /* Eratosthenes' algorithm for identifying prime numbers Written by: Peter Holcroft University of Hull, United Kingdom Contact: peter@holcroft.cjb.net Date written: 27/3/00 Updated: 12/9/00 (it now works! Sorry) Modified for zeta:20/10/01 R.M. This isn't meant to be an all singing all dancing prime number finder. It shows you one way of implemeting Eratosthenes' algorithm in Java and has been deliberately kept simple. Feel free to do whatever you want with this source code. Just change "max" to set the size of N, and "startat" for setting where to start displaying the prime numbers from. */ static final double ROOT_1=14.13472514d; static final double TEN_DIV_LOGTEN=4.34294481903252d; //10/ln(10) static final int max=20000; static byte[] PrimeOffs=null; static int primeCount=0; public void Sieve(int n) { // Create array and set all values to true boolean numberpool [] = new boolean [n]; for (int i=2; i underflow for im(z)> 451.86 coef= coef.mul((new Complex(pi*2)).pow(zMone)); coef= coef.mul(z.mul(new Complex(piD2)).sin()).mul(new Complex(2.0));*/ Complex coef= lnGamma(oneMz); coef= coef.add(zMone.mul(new Complex(ln2Pi))); if (z.im()>400.0) //sinus overflow coef= coef.add(new Complex(piD2*z.im(),piD2*(1.0d-z.re()))); else if (z.im()<-400.0) coef= coef.add(new Complex(-piD2*z.im(),piD2*(z.re()-1.0d))); else // coef= coef.add(z.mul(new Complex(piD2)).sin().mul(new Complex(2.0d)).log()); return coef.exp(); } //============== Riemann-Siegel formula =============================== // Ref : H.M. Edwards fine 'Riemann's zeta function' Dover (153f) // for C code and details see Glen Pugh's master thesis : 'The Riemann-Siegel // formula and large scale computation of the Riemann zeta function' at : // http://www.math.ubc.ca/~pugh (he has an applet too for this function) // for more advanced topics see Andrew Odlyzko's papers at // http://www.dtc.umn.edu/~odlyzko/ //set A0 An:= series(exp(2*PI*I*y^2),y); //to Order 40 for example //iterate An:= series(-1/2*y*expr(An)-1/(32*PI^2)*diff(expr(An)/y,y $2),y); //A1,A2.. //compute series(An*sum(Psi^(m)*y^m/m!,m=0..16),y); //keeping the real part of the constant term should give the n case below // (coeff obtained by expanding the taylor series around (z+1)/2) //Psi(p)= cos(2*pi*(p^2-p-1/16))/cos(2*pi*p) // Psi:=func(cos(2*PI*((p^2-p)-1/16))/cos(2*PI*p),p); static final int SIZE=23; static final double tabC[]= { //n=0 case corresponding to Taylor series of Psi((z+1)/2) // float(series(Psi(z/2+1/2),z)); +.38268343236508977173d, //0 (z^0 coefficient) +.43724046807752044936d, //2 (z^2 coefficient) +.13237657548034352332d, //4 -.01360502604767418865d, //6 -.01356762197010358089d, //8 -.00162372532314446528d, //10 +.00029705353733379691d, //12 +.00007943300879521470d, //14 +.00000046556124614505d, //16 -.00000143272516309551d, //18 -.00000010354847112313d, //20 +.00000001235792708386d, //22 +.00000000178810838580d, //24 -.00000000003391414390d, //26 -.00000000001632663390d, //28 -.000000000000378510932d,//30 +.0000000000000932742326d, //32 +.0000000000000052218430d, //34 -.00000000000000033506731d, //36 -.000000000000000034124265d, //38 +.00000000000000000057512033d, //40 +.00000000000000000014895301d, //42 +.000000000000000000001256537d,//44 //n=1 case -Psi^(3)(p)/(2^5*3*pi^2) // float(-1/(2^5*3*PI^2)*series(subs(diff(Psi(x),x $ 3),x=(z+1)/2),z)); -.02682510262837534703d, //1 +.01378477342635185305d, //3 +.03849125048223508223d, //5 +.00987106629906207647d, //7 -.00331075976085840433d, //9 -.00146478085779541508d, //11 -.00001320794062487696d, //13 +.00005922748701847141d, //15 +.00000598024258537345d, //17 -.00000096413224561698d, //19 -.00000018334733722714d, //21 +.00000000446708756272d, //23 +.00000000270963508218d, //25 +.00000000007785288654d, //27 -.00000000002343762601d, //29 -.00000000000158301728d, //31 +.00000000000012119942d, //33 +.00000000000001458378d, //35 -.00000000000000028786305d, //37 -.000000000000000086628629d, //39 -.00000000000000000084307227d, //41 +.00000000000000000036308072d, //43 +.000000000000000000011626698d, //45 //n=2 case Psi^(6)(p)/(2^11*3^2*pi^4)+Psi^(2)(p)/(2^6*pi^2) // float(1/(2^11*3^2*PI^4)*series(subs(diff(Psi(x),x $ 6),x=(z+1)/2),z)+\ // 1/(2^6*PI^2)*series(subs(diff(Psi(x),x $ 2),x=(z+1)/2),z)); +.00518854283029316849d, //0 +.00030946583880634746d, //2 -.01133594107822937338d, //4 +.00223304574195814477d, //6 +.00519663740886233021d, //8 +.00034399144076208337d, //10 -.00059106484274705828d, //12 -.00010229972547935857d, //14 +.00002088839221699276d, //16 +.00000592766549309654d, //18 -.00000016423838362436d, //20 -.00000015161199700941d, //22 -.00000000590780369821d, //24 +.00000000209115148595d, //26 +.00000000017815649583d, //28 -.00000000001616407246d, //30 -.00000000000238069625d, //32 +.00000000000005398265d, //34 +.00000000000001975014d, //36 +.00000000000000023333d, //38 -.00000000000000011188d, //40 -.00000000000000000416d, //42 +.00000000000000000044d, //44 //n=3 case // float(-1/(2^16*3^4*PI^6)*series(subs(diff(Psi(x),x $ 9),x=(z+1)/2),z)\ // -1/(2^8*3*5*PI^4)*series(subs(diff(Psi(x),x $ 5),x=(z+1)/2),z)\ // -1/(2^6*PI^2)*series(subs(diff(Psi(x),x $ 1),x=(z+1)/2),z)); -.00133971609071945690d, //1 +.00374421513637939370d, //3 -.00133031789193214681d, //5 -.00226546607654717871d, //7 +.00095484999985067304d, //9 +.00060100384589636039d, //11 -.00010128858286776622d, //13 -.00006865733449299826d, //15 +.00000059853667915386d, //17 +.00000333165985123995d, //19 +.00000021919289102435d, //21 -.00000007890884245681d, //23 -.00000000941468508130d, //25 +.00000000095701162109d, //27 +.00000000018763137453d, //29 -.00000000000443783768d, //31 -.00000000000224267385d, //33 -.00000000000003627687d, //35 +.00000000000001763981d, //37 +.00000000000000079608d, //39 -.00000000000000009420d, //41 -.00000000000000000713d, //43 +.00000000000000000033d, //45 //n=4 case // float( 1/(2^23*3^5*PI^8)*series(subs(diff(Psi(x),x $ 12),x=(z+1)/2),z)\ // +11/(2^17*3^2*5*PI^6)*series(subs(diff(Psi(x),x $ 8),x=(z+1)/2),z)\ // +19/(2^13*3*PI^4)*series(subs(diff(Psi(x),x $ 4),x=(z+1)/2),z)\ // +1/(2^7*PI^2)*series(subs(diff(Psi(x),x $ 0),x=(z+1)/2),z)); +.00046483389361763382d, //0 -.00100566073653404708d, //2 +.00024044856573725793d, //4 +.00102830861497023219d, //6 -.00076578610717556442d, //8 -.00020365286803084818d, //10 +.00023212290491068728d, //12 +.00003260214424386520d, //14 -.00002557906251794953d, //16 -.00000410746443891574d, //18 +.00000117811136403713d, //20 +.00000024456561422485d, //22 -.00000002391582476734d, //24 -.00000000750521420704d, //26 +.00000000013312279416d, //28 +.00000000013440626754d, //30 +.00000000000351377004d, //32 -.00000000000151915445d, //34 -.00000000000008915418d, //36 +.00000000000001119589d, //38 +.00000000000000105160d, //40 -.00000000000000005179d, //42 -.00000000000000000807d, //44 // n=5 case (better precision for im(z)<100) // -1/(2^28*3^6*5*PI^10)*Psi^(15) -7/(2^21*3^4*5*PI^8)*Psi^(11) // -901/(2^18*3^2*5*7*PI^6)*Psi^(7) -2879/(2^16*3^3*PI^4)*Psi^(3) +.00011358151751588485d, //1 +.00013843981041324421d, //3 -.00050704218914147061d, //5 +.00041217256703846327d, //7 +.00005023070325645194d, //9 -.00018582525099513277d, //11 +.00002750494063740395d, //13 +.0000315688068605559543d, //15 -.00000421775877767113104d, //17 -.000002915894480619020547d, //19 +.0000001565388574235306564d, //21 +.00000014652133137607268328d, //23 +.000000001220000970126585427d, //25 -.0000000041619249038691271836d, //27 -.00000000020939799866010355133d, //29 +.000000000070839559568612061552d, //31 +.0000000000060230007782059006404d, //33 -.00000000000074541544458884210219d, //35 -.000000000000094323130153963992815d, //37 +.000000000000004630342561822157759d, //39 +.0000000000000009637605950405984012d, //41 -.0000000000000000104494048409122514d, //43 -.00000000000000000693872458405353302d, //45 // n=6 case (better precision for im(z)<100) // 1/(2^34*3^8*5*PI^12)*Psi^(18)+ // 17/(652298158080*PI^10)*Psi^(14)+18889/(237817036800*PI^8)*Psi^(10)+ // 79267/(1698693120*PI^6)*Psi^(6)+2879/(1179648*PI^4)*Psi^(2)+ // Symbolic expression of result (long!) /* 1/(2^34*3^8*5*PI^12)*series(subs(diff(Psi(x),x $ 18),x=(z+1)/2),z)\ * +17/(2^29*3^5*5*PI^10)*series(subs(diff(Psi(x),x $ 14),x=(z+1)/2),z)\ * +18889/(2^24*3^4*5^2*7*PI^8)*series(subs(diff(Psi(x),x $ 10),x=(z+1)/2),z)\ * +79267/(2^22*3^4*5*PI^6)*series(subs(diff(Psi(x),x $ 6),x=(z+1)/2),z)\ * +2879/(2^17*3^2*PI^4)*series(subs(diff(Psi(x),x $ 2),x=(z+1)/2),z); * Numerical result (faster) * DIGITS:=80;ORDER:=68;float(expr(series(Psi((x+1)/2),x))); * float(2^18/(2^34*3^8*5*PI^12)*series(diff(%,x $ 18),x)\ * +17*2^14/(2^29*3^5*5*PI^10)*series(diff(%,x $ 14),x)\ * +18889*2^10/(2^24*3^4*5^2*7*PI^8)*series(diff(%,x $ 10),x)\ * +79267*2^6/(2^22*3^4*5*PI^6)*series(diff(%,x $ 6),x)\ * +2879*2^2/(2^17*3^2*PI^4)*series(diff(%,x $ 2),x)); */ +.00003366247684612519d, //0 -.00012182766933520408d, //2 +.00021826882115815319d, //4 -.00016620260965468581d, //6 -.00003113033504123243d, //8 +.00012085626945766257d, //10 -.00004514821873763377d, //12 -.00001855020684500451d, //14 +.00001161614666033275d, //16 +.00000155157285696512d, //18 -.00000117318271081542d, //20 -.00000012201323270163d, //22 +.00000005938094296415d, //24 +.000000007011985632696d, //26 -.000000001644510215296d, //28 -.000000000241384690347d, //30 +.0000000000258853999298d, //32 +.000000000005119286964651d,//34 -.000000000000215416066156d, //36 -.0000000000000713422758095d, //38 +.00000000000000028785659432d, //40 +.000000000000000688351410984d, //42 +.0000000000000000152089120028d}; //44 //C coeff for Riemann-Siegel formula public double Coeff(int n, double z) { double p; double s=0.0d; double z2=z*z; if (n<7) { int st=n*SIZE; if ((n&1)!=0) p= z; else p= 1.0; int i=SIZE; while (--i>=0) { s += tabC[st]*p; p *= z2; st++; } } return s; } static final double pi = 3.1415926535897932385d; // java.lang.Math.PI static final double piD2 = 1.5707963267948966192d; // pi/2 static final double invTwoPi= 0.1591549430918953358d; // 1/(2*Pi) // theta(t)=Im{log[Pi(it/2-3/4)]}-t/2*log(pi) // using the approximate // t/2*(log(t/(2*Pi))-1)-Pi/8+1/(48*t)+7/(5760*t^3)+31/(80640*t^5)+127/(430080*t^7)+511/(1216512*t^9) // +1414477/(1476034560*t^11)+1898482392450447133975223/(2642676384606731475419894*t^13) // should not be called for t<=10 (absolute error of order 4*10^(-9)) public double theta(double t) { return t*0.5d*(Math.log(t*invTwoPi)-1.0) - pi/8.0d + 1.0d/(48.0d*t) + 7.0d/(5760.0d*t*t*t); } //Riemann-Siegel Z function (0<=n<6) //precision smaller for t<100 (t>10^6 ?) (n=6 recommanded) public double Z(double t, int n) { if (t<14.0d) { if (t<-14.0d) return Z(-t, n); //in [-14,14] Euler-MacLaurin is more accurate int dec; if (n>=6) dec=10; else dec=7; return -EulerML(new Complex(0.5d, t),dec).abs(); } double w= t*invTwoPi; //t/(2*pi) double X= Math.sqrt(w); //sqrt(t/(2*pi)) double ip= 1.0d/X; //sqrt(2*pi/t) double sip= Math.sqrt(ip); //(2*pi/t)^(1/4) int N = (int) X; //int(sqrt(t/(2*pi))) X -= N; //fract(sqrt(t/(2*pi))) X = 2.0d*X-1.0d; //in [-1,1[ double tt = theta(t); double ZZ= Math.cos(tt); int j=1; while (++j <= N) { ZZ += Math.cos((tt-t*Math.log((double) j))) /Math.sqrt((double) j); } ZZ *= 2.0d; double po= 1.0d; double R= 0.0d; int k=-1; while (++k <= n) { R += Coeff(k,X)*po; po *= ip; } if ((N & 1)!=0) return ZZ+R*sip; else return ZZ-R*sip; } // Euler-MacLaurin expansion of zeta // should not be called for im(z) >> 1 (slow!) public Complex EulerML(Complex z, int dec) { // divergent if im(z) > 2*Pi*N int N; if (dec<8) N= (int) (Math.abs(z.im())*0.5)+5; //7 decimals or more else N= (int) (Math.abs(z.im()))+8; //more than 10 decimals // finite sum : sum(1/k^x, k=1..N) Complex nz= z.neg(); double xx=nz.re(); double yy=nz.im(); double lk; double ek; double py; double sx=1.0d; double sy=0.0d; //faster than s= s.add(Complex.pow((double) k, nz)); and heap friendly for (int k=2; k<=N; k++) { lk= Math.log((double) k); ek= Math.exp(xx*lk); sx += Math.cos(py=lk*yy)*ek; sy += Math.sin(py)*ek; } Complex s= new Complex(sx, sy); // remaining integral : + 1/((x-1)*N^(x-1)) Complex unit= new Complex(1.0d); Complex xd= z.sub(unit); Complex p= unit.div(xd.mul(Complex.pow((double)N, xd))); s= s.add(p); //Bernoulli terms : // -1/(2*N^x) (B_1/1!*N^(-x)) xd= z; p= unit.div(Complex.pow((double)N, xd).mul(new Complex(2.0d))); s= s.sub(p); // +x/(12*N^(x+1)) (B_2/2!*...) p= p.mul(xd).div(new Complex(6.0d*N)); s= s.add(p); // -x*(x+1)*(x+2)/(720*N^(x+3)) (B_4/4!*...) double NN= N*N; xd= xd.add(unit); //z+1 p= p.mul(xd); xd= xd.add(unit); //z+2 p= p.mul(xd).div(new Complex(60.0d*NN)); s= s.sub(p); // +x*(x+1)*(x+2)*(x+3)*(x+4)/(30240*N^(x+5)) (B_6/6!*...) xd= xd.add(unit); //z+3 p= p.mul(xd); xd= xd.add(unit); //z+4 p= p.mul(xd).div(new Complex(42.0d*NN)); s= s.add(p); // -x*(x+1)*(x+2)*(x+3)*(x+4)*(x+5)*(x+6)/(1209600*n^(x+7)) xd= xd.add(unit); //z+4 p= p.mul(xd); xd= xd.add(unit); //z+5 p= p.mul(xd).div(new Complex(40.0d*NN)); s= s.sub(p); // +x*(x+1)*(x+2)*(x+3)*(x+4)*(x+5)*(x+6)*(x+7)*(x+8)/(47900160*n^(x+9)) xd= xd.add(unit); //z+6 p= p.mul(xd); xd= xd.add(unit); //z+7 p= p.mul(xd).div(new Complex(39.6d*NN)); s= s.add(p); // result return s; } // use the appropriate method to evaluate the zeta function // on the complex plane (for Re(z) > -6) public Complex zeta(Complex z, int dec) { if (z.im()<0) return zeta(z.conj(),dec).conj(); else { //far critical line ? if ((z.re()==0.5d) && ((z.im()>40.0d) || (z.im()>10.0d) && (dec<8))) { // use Riemann-Siegel formula ~ sqrt(y) double ZZ; if (dec>7) //more precision ZZ= Z(z.im(),6); else ZZ= Z(z.im(),4); double tt= theta(z.im()); return new Complex(ZZ*Math.cos(tt), -ZZ*Math.sin(tt)); } else { // use Euler-MacLaurin expansion ~ y return EulerML(z,dec); } } } public void paint(Graphics gr) { if (G_POINTSNUMBER<=0) return; //use local variables (global may be modified) Complex z= G_z; // z Complex mz= z.neg(); // -z int choice=G_CHOICE; int nb= G_POINTSNUMBER; double inScaling=G_INSCALING; double outScaling=G_OUTSCALING; double xRef= G_xRef; double yRef= G_yRef; double Ox= G_ox; double Oy= G_oy; int count= nb; //impose count <= nb try { //array and number of points if (cache_nb!=nb) { //new arrays only if size change xP= new int[nb]; yP= new int[nb]; cache_nb= nb; //allocated size cache_choice= -1; } //points generation corresponding to choice switch (choice) { case 0: //finite sum (convergent for Re(z)>1) { double d=2.0; Complex sum= new Complex(1.0d); xP[0]=(int)(G_m*sum.re()+Ox); yP[0]=(int)(Oy-G_m*sum.im()); for (int i= 1; i< nb; i++) { sum= sum.add(Complex.pow(d, mz)); xP[i]=(int)(G_m*sum.re()+Ox); yP[i]=(int)(Oy-G_m*sum.im()); d += 1.0; } } break; case 1: //mirror finite sum (using functional equation) Re(z)<1 { //use the functional equation : Complex coef=functionalEquation(z); double d=1.0; Complex res= null; Complex zMone= z.sub(new Complex(1.0d)); // z-1 Complex sum= new Complex(0.0d); for (int i= 0; i< nb; i++) { sum= sum.add(Complex.pow(d, zMone)); res= sum.mul(coef); xP[i]=(int)(G_m*res.re()+Ox); yP[i]=(int)(Oy-G_m*res.im()); d += 1.0; } } break; case 2: //alternate sum (convergent for Re(z)>0) { double d=2.0; Complex cSum; boolean pos = false; //compute coef= 1/(2^(1-x)-1) Complex unit= new Complex(1.0d); Complex coef=unit.div(Complex.pow(2.0,unit.add(mz)).sub(unit)); Complex sum= new Complex(-1.0d); cSum= sum.mul(coef); xP[0]=(int)(G_m*cSum.re()+Ox); yP[0]=(int)(Oy-G_m*cSum.im()); for (int i= 1; i< nb; i++) { pos = !pos; if (pos) sum= sum.add(Complex.pow(d, mz)); //mz = -z else sum= sum.sub(Complex.pow(d, mz)); cSum= sum.mul(coef); xP[i]=(int)(G_m*cSum.re()+Ox); yP[i]=(int)(Oy-G_m*cSum.im()); d += 1.0; } } break; case 3: //mirror alternate sum { //use the functional equation : Complex coef=functionalEquation(z); double d=2.0; Complex cSum; boolean pos = false; Complex unit= new Complex(1.0d); //multiply by 1/(2^(1-x)-1) with z=1-x here coef= coef.div(Complex.pow(2.0,z).sub(unit)); Complex sum= new Complex(-1.0d); Complex zMone= z.sub(unit); // z-1 cSum= sum.mul(coef); xP[0]=(int)(G_m*cSum.re()+Ox); yP[0]=(int)(Oy-G_m*cSum.im()); for (int i= 1; i< nb; i++) { pos = !pos; if (pos) sum= sum.add(Complex.pow(d, zMone)); //zMone = z-1 else sum= sum.sub(Complex.pow(d, zMone)); cSum= sum.mul(coef); xP[i]=(int)(G_m*cSum.re()+Ox); yP[i]=(int)(Oy-G_m*cSum.im()); d += 1.0; } } break; case 4: //finite Euler product { if (PrimeOffs==null) //use the Sieve to compute primes offset table Sieve(max); if (PrimeOffs!=null) { double d=2.0; Complex prd= new Complex(1.0d); Complex unit= new Complex(1.0d); xP[0]=(int)(G_m*prd.re()+Ox); yP[0]=(int)(Oy-G_m*prd.im()); if (nb>=primeCount) count= primeCount-1; else count= nb; for (int i= 1; i< count; i++) { prd= prd.div(unit.sub(Complex.pow(d, mz))); xP[i]=(int)(G_m*prd.re()+Ox); yP[i]=(int)(Oy-G_m*prd.im()); d += PrimeOffs[i]; } } } break; case 5: //Riemann-Siegel function { //Output y corresponds to y input (output scaling on x only) //On critical line use Riemann-Siegel (and zeta for abs(im(z))<10) if (xRef==0.5d) { double xx; double yy; double maxT= yRef+inScaling/2.0; //logical (at top of frame) double offset=inScaling/nb; double max= Math.round(maxT/offset)*offset; //for cache cacheRestore(choice, inScaling, outScaling, xRef, max, -offset); //set cache_first and cache_last for (int i= cache_first; i<= cache_last; i++) { yy= max-i*offset; xx= Z(yy, 6); xP[i]=(int)(G_m*xx+G_WIDTH/2); //output scaling acts on X only } double oy=(maxT-max)/offset; for (int i= 0; i< nb; i++) yP[i]=(int) (((oy+i)*G_HEIGHT)/nb); cache_start= max; cache_offset= -offset; } } break; case 6: //Riemann zeta function { //along y axis only yet (any constraint later...) double max= yRef+inScaling/2.0; //logical value at top of frame double yy; Complex zz; double offset= inScaling/nb; max= Math.round(max/offset)*offset; //for cache cacheRestore(choice, inScaling, outScaling, xRef, max, -offset); //set cache_first and cache_last int prec=7; //EML 2 times faster if (outScaling<0.1d || Math.abs(yRef)>1E5) //near look or far.. ? prec=10; for (int i= cache_first; i<= cache_last; i++) { yy= max-i*offset; zz= zeta(new Complex(xRef, yy), prec); xP[i]=(int)(G_m*zz.re()+G_WIDTH/2); yP[i]=(int)(Oy-G_m*zz.im()); } cache_start= max; cache_offset= -offset; } break; case 7: //Riemann zeta 3D { //along y axis only yet (any constraint later...) double minT=yRef-inScaling/2.0; //logical value corresponding to foreground // (distance 1 from observer) double yy; Complex zz; double rb= 2000.0d/outScaling; double offset= inScaling/nb; double min= Math.round(minT/offset)*offset; //for cache int prec=7; if (outScaling<0.05d || Math.abs(yRef)>1E5) //near look or far.. ? prec=10; cacheRestore(choice, inScaling, outScaling, xRef, min, offset); //set cache_first and cache_last for (int i= cache_first; i<= cache_last; i++) { yy= min+(i*inScaling)/nb; zz= zeta(new Complex(xRef, yy),prec); xP[i]=(int)Math.round(zz.re()*rb); yP[i]=(int)Math.round(zz.im()*rb); } //drawing int x,y; rb= G_HEIGHT/2000.0d; double ofs=1.0d+min-minT; double r=rb/ofs; int ox=(int)(r*xP[0]+Ox); int oy=(int)(Oy-r*yP[0]); Complex pt=initScr(gr,z,choice,inScaling,outScaling,Ox,Oy,xRef,yRef); for (int i= 1; i< nb; i++) { r= rb/(ofs+(i*inScaling)/nb); x=(int)(r*xP[i]+Ox); y=(int)(Oy-r*yP[i]); gr.drawLine(ox, oy, x, y); ox= x; oy= y; } if (pt!=null) drawTarget(gr, pt); count=0; //drawing already done (xP,yP for buffering only) } break; case 8: //goodies { //none yet... //count=0; Complex unit= new Complex(1.0d); Complex coef=functionalEquation(z); Complex coef2=Complex.pow(2.0d, z); Complex coef3=Complex.pow(G_Radius, z); double d=1.0; Complex res= null; Complex zMone= z.sub(new Complex(1.0d)); // z-1 Complex sum= new Complex(0.0d); count= (int)(Math.abs(z.im())/((3.0+G_Arg*180.0/pi)*pi)+1); if (count>nb) count=nb; for (int i= 0; iright or ^ top) public void findZero(int next) { //start near the selected point G_xRef= G_z.re(); G_yRef= G_z.im(); double inc=0.0; if (next>0) { if (G_xRef<-2.0d) { double nx= Math.ceil(G_xRef/2.0d)*2.0d; if (G_xRef==nx) nx += 2.0d; G_xRef= nx; G_yRef= 0.0d; } else { G_xRef=0.5d; //OK R.H supposed but... if ((Math.abs(G_yRef)<=ROOT_1+1E-7) && (Math.abs(G_yRef-ROOT_1)>1E-7)) G_yRef=ROOT_1; else { //search needed inc=next; } } } else { if (G_xRef<0.0d) { double nx= Math.floor(G_xRef/2.0d)*2.0d; if (G_xRef==nx) nx -= 2.0d; G_xRef= nx; G_yRef= 0.0d; } else { G_xRef=0.5d; //OK R.H supposed but... if ((Math.abs(G_yRef)<=ROOT_1+1E-7) && (Math.abs(G_yRef+ROOT_1)>1E-7)) G_yRef=-ROOT_1; else { //search needed inc=next; } } } if (inc!=0.0d) { //real work //we could use Gram points too but... double st=G_yRef; //Math.abs(G_yRef); inc /= (16.0d*Math.log(Math.abs(st))); double zz= Z(st,6); //full precision while (Math.abs(zz)<1e-7d) { //near a zero? st += inc; zz= Z(st,6); } inc *= 8.0; //faster far from zero double z=st; double nz= zz; double iz= zz; double pz; double incLim= inc/1024.0d; zz= Z(st-inc,6); do { z += inc; pz= zz; zz= nz; nz= Z(z,6); //extremum handling (=> pb. not R.H. false but...) //more precision is required (near 17143 for example) if ((pz>zz && zz<=nz && zz>=0.0 || //positive minimum pz=nz && zz<0.0) && //negative maximum (zz!=iz)) { //out of attraction of starting point! inc *= 0.5d; z -= 3*inc; zz= pz; nz= Z(z,6); if (Math.abs(inc) < Math.abs(incLim)) break; //minimum (R.H. false or out of precision...) } } while (nz*zz>0.0d); if (Math.abs(inc) < Math.abs(incLim)) { //abnormal minimum or maximum !!! G_yRef= z; } else { //use interpolation double z1 = z-inc; double zz1= Z(z1,6); double z2 = z; double zz2= nz; int cpt=100; //security limit do { z= z1+zz1*(z2-z1)/(zz1-zz2); nz= Z(z,6); //full precision if (nz*zz1<0.0d) { z2=z; zz2=nz; } else if (nz*zz2<0.0d) { z1=z; zz1=nz; } else break; --cpt; } while (Math.abs(nz)>1e-8d && zz1!=zz2 &&cpt>=0); G_yRef= z; } } G_z= new Complex(G_xRef, G_yRef); //G_ix= G_WIDTH/2-G_xRef/G_INSCALING; //new center (pixels) //G_iy= G_HEIGHT/2+G_yRef/G_INSCALING; updateAll(); } //restore earlier computed values (scrolling speed-up) public void cacheRestore(int choice, double inScaling, double outScaling, double OffsX, double start, double offset) { cache_first=0; cache_last=cache_nb-1; if (cache_choice==choice && cache_inScaling==inScaling && cache_outScaling==outScaling && cache_OffsX==OffsX && cache_offset==offset) { int posStart= (int)Math.round((cache_start-start)/offset); if (posStart>0) { if (posStart=posStart; --i) { xP[i]= xP[i-posStart]; yP[i]= yP[i-posStart]; } cache_last=posStart-1; //0..posStart to fill } } else if (posStart<0) { if (posStart+cache_nb>0) { for (int i=0; iN) { int ex=res.indexOf('E'); int pt=res.indexOf('.'); if (ex>=0) { int l=N-res.length(); int st= N-(res.length()-ex); if (st>=pt) res= res.substring(0,st)+res.substring(ex,res.length()); else res= res.substring(0,pt)+res.substring(ex,res.length()); } if (pt>=N) //cast to integer res=Integer.toString(db.intValue()); else res=res.substring(0,N); } } catch (Exception e) { res="1.0"; } return res; } public void update(Graphics g) { /* don't erase background g.setColor(getBackground()); g.fillRect(0, 0, width, height); g.setColor(getForeground()); */ paint(g); } /** * Handle an event on an object in this class. * @param event The event which occurred. * @return true if the event is handled, false if not **/ public boolean handleEvent(Event event) { Object arg = event.arg; boolean eventHandled = false; //{{ wiring - Begin Non-Editable Code Block //}} wiring - End Non-Editable Code Block if (!eventHandled) { super.handleEvent(event); } // always return false so that others may handle the event as well return false; } //Complete redraw of the canvas rectangle public void updateAll() { repaint(); } public void ScaledLine(Graphics gr, int sx, int sy, int dx, int dy) { gr.drawLine((int)(G_m*sx+G_ox), (int)(G_oy-G_m*sy) ,(int)(G_m*dx+G_ox), (int)(G_oy-G_m*dy)); } public String formatFix(double d, int N) { String res= null; try { double da=Math.abs(d); Double Db= new Double(da); if (da<1.0) { //exponential notation not wished (for precision warranty!) res=Double.toString(da+1.0d); res="0"+res.substring(1); } else res=Double.toString(da); if (res.length()>N) { int pt=res.indexOf('.'); if (pt>=N) //cast to integer res=Long.toString(Db.longValue()); else res=res.substring(0,N); } if (d>=0.0d) res= "+"+res; else res= "-"+res; } catch (Exception e) { res="+0"; } return res; } //generate x+yi in fixed format public String formatComplex(Complex c, int N) { return formatFix(c.re(),N)+" "+formatFix(c.im(),N)+"i"; } // + for zeta(z) or Z(t) public void drawTarget(Graphics g, Complex pt) { int x=(int) pt.re(); int y=(int) pt.im(); g.setColor(new Color(127,127,0)); g.drawLine(x-8,y,x+8,y); g.drawLine(x,y-8,x,y+8); g.setColor(getForeground()); } //Clear frame and draw x=0, x=1 lines, ... //z and zeta(z) text public Complex initScr(Graphics g, Complex z, int choice, double inScaling, double outScaling, double Ox, double Oy, double xRef, double yRef) { Complex res=null; Dimension d = size(); g.setColor(getBackground()); g.fillRect(0, 0, d.width, d.height); g.setColor(getForeground()); // background lines ScaledLine(g, ((int)-outScaling)-1,0, ((int)outScaling)+1,0); //real axis ScaledLine(g, 0,((int)-outScaling)-1, 0,((int)outScaling)+1); //imaginary axis ScaledLine(g, 1,((int)-outScaling)-1, 1,((int)outScaling)+1); //Re(z)=1 line //input value (at the bottom) int prec=10; if (Math.abs(z.im())>=10000.0) prec=14; else if (Math.abs(z.im())>=1000.0) prec=13; else if (Math.abs(z.im())>=100.0) prec=12; else if (Math.abs(z.im())>=40.0) prec=11; if (G_CHOICE==5) { //Riemann-Siegel g.drawString("t = "+formatDouble(z.im(),prec),16,480); //output value (at the top) double ft=Z(z.im(),6); prec=10; if (Math.abs(z.im())<40.0d) prec=9; //hide the imprecise roots there... g.drawString("Z(t)= "+formatFix(ft,prec),6,28); res=new Complex((int)(G_m*ft+Ox), (int)(G_HEIGHT/2-(z.im()-yRef)*G_HEIGHT/inScaling)); } else { Complex zz=z; if (G_CHOICE>5) //constraint on x zz= new Complex(xRef, z.im()); g.drawString("z = "+formatComplex(zz,prec),16,480); //output value (at the top) Complex fz=zeta(zz,10); prec=10; if (zz.re()==0.5d && (Math.abs(zz.im())<40.0d)) prec=9; //hide the imprecise roots there... Unicode ? "\u03B6" g.drawString("zeta(z)= "+formatComplex(fz,prec),6,28); if (G_CHOICE<7) res=new Complex((int)(G_m*fz.re()+Ox), (int)(Oy-G_m*fz.im())); else if (G_CHOICE==7) { double r= 1.0/(1.0d+zz.im()-yRef+inScaling/2.0d); //distance to observer res=new Complex((int)(G_m*fz.re()*r+Ox), (int)(Oy-G_m*fz.im()*r)); } } return res; } // new 'number of points' public void newPointsNumber(int pointsNumber) { G_POINTSNUMBER = pointsNumber; updateAll(); } //Reset Default public void resetDefault(boolean complet) { G_POINTSNUMBER = 1000; //200 in previous releases G_INSCALING = 2; //1 earlier G_OUTSCALING = 2; //1 earlier G_ix = G_WIDTH/2; //-G_HEIGHT/2; G_iy = G_HEIGHT/2; G_ox = G_ix; G_oy = G_iy; switch (G_CHOICE) { case 0: //finite sum (convergent for Re(z)>1) case 1: //mirror finite sum (using functional equation) Re(z)<1 case 2: //alternate sum (convergent for Re(z)>0) case 3: //mirror alternate sum case 4: //finite Euler product break; //previous default case 5: //Riemann-Siegel function { G_POINTSNUMBER = 250; G_OUTSCALING = 8; G_INSCALING = 40; } break; case 6: //Riemann zeta function { G_OUTSCALING = 8; G_INSCALING = 10; } break; case 7: //Riemann zeta 3D { G_OUTSCALING = 1; G_INSCALING = 10; } break; case 8: //goodies } if (G_OUTSCALING!= 0.0d) G_m= G_HEIGHT/G_OUTSCALING; //unit height in pixels else G_m= 0.0d; //back to the first zero? if (complet) { G_xRef= 0.5d; G_yRef= 14.13472514d; G_z= new Complex(G_xRef, G_yRef); } updateAll(); } //new choice public void update(int choice) { G_CHOICE= choice; //upadeAll(); } public void restrainInput(int restrain) { G_RESTRAIN= restrain; } //clic in the top panel public void newPoint(int x, int y) { switch (G_RESTRAIN) { case 0 : //none G_z= new Complex(G_xRef+(x-G_ix)*G_INSCALING/G_HEIGHT, G_yRef-(y-G_iy)*G_INSCALING/G_HEIGHT); break; case 1 : //x =G_ox only G_z= new Complex(G_xRef, G_yRef-(y-G_iy)*G_INSCALING/G_HEIGHT); break; case 2 : //y =G_oy only G_z= new Complex(G_xRef+(x-G_ix)*G_INSCALING/G_HEIGHT, G_yRef); break; case 3 : { //radius double dist=Math.sqrt((x-G_ix)*(x-G_ix)+(y-G_iy)*(y-G_iy)); if (dist==0.0) G_z= new Complex(G_xRef, G_yRef); else G_z= new Complex(G_xRef+(x-G_ix)*G_Radius/dist, G_yRef-(y-G_iy)*G_Radius/dist); } break; case 4 : { //arg double prod=((x-G_ix)*Math.cos(G_Arg)-(y-G_iy)*Math.sin(G_Arg))/G_HEIGHT; G_z= new Complex(G_xRef+prod*Math.cos(G_Arg), G_yRef+prod*Math.sin(G_Arg)); } break; } updateAll(); } public void newOutputScaling(double outputScaling) { G_OUTSCALING = outputScaling; G_m= G_HEIGHT/outputScaling; //unit height in pixels updateAll(); } public void newInputScaling(double inputScaling) { if (inputScaling!=0.0) G_INSCALING = inputScaling; if (G_CHOICE>4) updateAll(); } public void newXOffset(double xOffset) { G_xRef= xOffset; G_z= new Complex(xOffset, G_z.im()); //G_ix= G_WIDTH/2-xOffset/G_INSCALING; //new center (pixels) updateAll(); } public void newYOffset(double yOffset) { G_yRef= yOffset; G_z= new Complex(G_z.re(), yOffset); //G_iy= G_HEIGHT/2+yOffset/G_INSCALING; //new center (pixels) updateAll(); } public void newRadius(double radius) { G_Radius= radius; updateAll(); } //input in degrees public void newArg(double arg) { G_Arg= arg*Math.PI/180.0; updateAll(); } //{{ declarations - Begin Non-Editable Code Block //}} declarations - End Non-Editable Code Block public static double G_HEIGHT= 495; //Back height public static double G_WIDTH = 700; //Back width public static int G_POINTSNUMBER= 1000; //200 public static int G_CHOICE= 2; public static int G_RESTRAIN= 0; //none public static double G_m= G_HEIGHT; //corresponding to G_OUTSCALING = 1 public static double G_OUTSCALING = 1; //scaling on output public static double G_INSCALING = 1; //scaling on input public static double G_ix= G_WIDTH/2; //input offset public static double G_iy= G_HEIGHT/2; public static double G_ox= G_ix; //output offset public static double G_oy= G_iy; public static double G_Radius= 0.0; //constraint public static double G_Arg= 0.0; public static double G_xRef= 0.5; public static double G_yRef= ROOT_1; public static Complex G_z= new Complex(G_xRef, G_yRef); public static int[] xP= null; public static int[] yP= null; public static int cache_nb=-1; //arrays empty public static int cache_choice=-1; //none public static double cache_inScaling=1.0d; //for comparison purpose public static double cache_outScaling=1.0d; public static double cache_OffsX=-100.0d; public static double cache_start=0.0d; public static double cache_offset=1.0d; public static int cache_first=0; //first not covered by cache public static int cache_last=0; //last not covered by cache public static boolean withReset= true; //reset on selection change //{{ extra_code //}} extra_code }