// zeta(). // General includes. #include "cl_sysdep.h" // Specification. #include "cl_F_tran.h" // Implementation. #include "cln/lfloat.h" #include "cl_LF_tran.h" #include "cl_LF.h" #include "cln/integer.h" #include "cln/abort.h" #include "cl_alloca.h" namespace cln { const cl_LF compute_zeta_exp (int s, uintC len) { // Method: // zeta(s) = 1/(1-2^(1-s)) sum(n=0..infty, (-1)^n/(n+1)^s), // with convergence acceleration through exp(x), and evaluated // using the binary-splitting algorithm. var uintC actuallen = len+2; // 2 Schutz-Digits var uintL x = (uintL)(0.693148*intDsize*actuallen)+1; var uintL N = (uintL)(2.718281828*x); CL_ALLOCA_STACK; var cl_pqd_series_term* args = (cl_pqd_series_term*) cl_alloca(N*sizeof(cl_pqd_series_term)); var uintL n; for (n = 0; n < N; n++) { if (n==0) { init1(cl_I, args[n].p) (1); init1(cl_I, args[n].q) (1); } else { init1(cl_I, args[n].p) (x); init1(cl_I, args[n].q) (n); } init1(cl_I, args[n].d) (evenp(n) ? expt_pos(n+1,s) : -expt_pos(n+1,s)); } var cl_LF result = eval_pqd_series(N,args,actuallen); for (n = 0; n < N; n++) { args[n].p.~cl_I(); args[n].q.~cl_I(); args[n].d.~cl_I(); } result = shorten(result,len); // verkürzen und fertig // Zum Schluss mit 2^(s-1)/(2^(s-1)-1) multiplizieren: return scale_float(result,s-1) / (ash(1,s-1)-1); } // Bit complexity (N = len): O(log(N)^2*M(N)). const cl_LF compute_zeta_cvz1 (int s, uintC len) { // Method: // zeta(s) = 1/(1-2^(1-s)) sum(n=0..infty, (-1)^n/(n+1)^s), // with Cohen-Villegas-Zagier convergence acceleration. var uintC actuallen = len+2; // 2 Schutz-Digits var uintL N = (uintL)(0.39321985*intDsize*actuallen)+1; var cl_I fterm = 2*(cl_I)N*(cl_I)N; var cl_I fsum = fterm; var cl_LF gterm = cl_I_to_LF(fterm,actuallen); var cl_LF gsum = gterm; var uintL n; // After n loops // fterm = (N+n)!N/(2n+2)!(N-n-1)!*2^(2n+2), fsum = ... + fterm, // gterm = S_n*fterm, gsum = ... + gterm. for (n = 1; n < N; n++) { fterm = exquopos(fterm*(2*(cl_I)(N-n)*(cl_I)(N+n)),(cl_I)(2*n+1)*(cl_I)(n+1)); fsum = fsum + fterm; gterm = The(cl_LF)(gterm*(2*(cl_I)(N-n)*(cl_I)(N+n)))/((cl_I)(2*n+1)*(cl_I)(n+1)); if (evenp(n)) gterm = gterm + cl_I_to_LF(fterm,actuallen)/expt_pos(n+1,s); else gterm = gterm - cl_I_to_LF(fterm,actuallen)/expt_pos(n+1,s); gsum = gsum + gterm; } var cl_LF result = gsum/cl_I_to_LF(1+fsum,actuallen); result = shorten(result,len); // verkürzen und fertig // Zum Schluss mit 2^(s-1)/(2^(s-1)-1) multiplizieren: return scale_float(result,s-1) / (ash(1,s-1)-1); } // Bit complexity (N = len): O(N^2). const cl_LF compute_zeta_cvz2 (int s, uintC len) { // Method: // zeta(s) = 1/(1-2^(1-s)) sum(n=0..infty, (-1)^n/(n+1)^s), // with Cohen-Villegas-Zagier convergence acceleration, and // evaluated using the binary splitting algorithm. var uintC actuallen = len+2; // 2 Schutz-Digits var uintL N = (uintL)(0.39321985*intDsize*actuallen)+1; CL_ALLOCA_STACK; var cl_pqd_series_term* args = (cl_pqd_series_term*) cl_alloca(N*sizeof(cl_pqd_series_term)); var uintL n; for (n = 0; n < N; n++) { init1(cl_I, args[n].p) (2*(cl_I)(N-n)*(cl_I)(N+n)); init1(cl_I, args[n].q) ((cl_I)(2*n+1)*(cl_I)(n+1)); init1(cl_I, args[n].d) (evenp(n) ? expt_pos(n+1,s) : -expt_pos(n+1,s)); } var cl_pqd_series_result sums; eval_pqd_series_aux(N,args,sums); // Here we need U/(1+S) = V/D(Q+T). var cl_LF result = cl_I_to_LF(sums.V,actuallen) / The(cl_LF)(sums.D * cl_I_to_LF(sums.Q+sums.T,actuallen)); for (n = 0; n < N; n++) { args[n].p.~cl_I(); args[n].q.~cl_I(); args[n].d.~cl_I(); } result = shorten(result,len); // verkürzen und fertig // Zum Schluss mit 2^(s-1)/(2^(s-1)-1) multiplizieren: return scale_float(result,s-1) / (ash(1,s-1)-1); } // Bit complexity (N = len): O(log(N)^2*M(N)). // Timings of the above algorithm, on an i486 33 MHz, running Linux. // s 5 15 // N sum_exp sum_cvz1 sum_cvz2 sum_exp sum_cvz1 sum_cvz2 // 10 2.04 0.09 0.17 8.0 0.11 0.49 // 25 8.6 0.30 0.76 30.6 0.37 2.36 // 50 25.1 0.92 2.49 91.1 1.15 7.9 // 100 2.97 8.46 3.75 24.5 // 250 16.7 36.5 21.7 108 // 500 64.2 106 85.3 295 // 1000 263 285 342 788 // asymp. FAST N^2 FAST FAST N^2 FAST // // The break-even point between cvz1 and cvz2 seems to grow linearly with s. const cl_LF zeta (int s, uintC len) { if (!(s > 1)) cl_abort(); if (len < 280*(uintL)s) return compute_zeta_cvz1(s,len); else return compute_zeta_cvz2(s,len); } // Bit complexity (N = len): O(log(N)^2*M(N)). } // namespace cln