X-Git-Url: https://ginac.de/CLN/cln.git//cln.git?a=blobdiff_plain;f=src%2Ffloat%2Ftranscendental%2Fcl_LF_ratseries_pqa.cc;h=a9e5877f49c7e07cc7fc407f123c63d37c88348a;hb=eedac861e082bb3e12392e0037842470310f80d6;hp=36fed64463d9d49bec0edb6d9e27c9ed77e21888;hpb=dd9e0f894eec7e2a8cf85078330ddc0a6639090b;p=cln.git diff --git a/src/float/transcendental/cl_LF_ratseries_pqa.cc b/src/float/transcendental/cl_LF_ratseries_pqa.cc index 36fed64..a9e5877 100644 --- a/src/float/transcendental/cl_LF_ratseries_pqa.cc +++ b/src/float/transcendental/cl_LF_ratseries_pqa.cc @@ -1,4 +1,4 @@ -// eval_rational_series(). +// eval_rational_series(). // General includes. #include "cl_sysdep.h" @@ -9,10 +9,14 @@ // Implementation. -#include "cl_lfloat.h" -#include "cl_integer.h" -#include "cl_abort.h" +#include "cln/lfloat.h" +#include "cln/integer.h" +#include "cln/real.h" +#include "cln/exception.h" #include "cl_LF.h" +#include "cl_alloca.h" + +namespace cln { // Subroutine. // Evaluates S = sum(N1 <= n < N2, a(n)/b(n) * (p(N1)...p(n))/(q(N1)...q(n))) @@ -20,13 +24,13 @@ // and T = B*Q*S (all integers). On entry N1 < N2. // P will not be computed if a NULL pointer is passed. -static void eval_pqa_series_aux (uintL N1, uintL N2, +static void eval_pqa_series_aux (uintC N1, uintC N2, const cl_pqa_series& args, cl_I* P, cl_I* Q, cl_I* T) { switch (N2 - N1) { case 0: - cl_abort(); break; + throw runtime_exception(); break; case 1: if (P) { *P = args.pv[N1]; } *Q = args.qv[N1]; @@ -66,7 +70,7 @@ static void eval_pqa_series_aux (uintL N1, uintL N2, break; } default: { - var uintL Nm = (N1+N2)/2; // midpoint + var uintC Nm = (N1+N2)/2; // midpoint // Compute left part. var cl_I LP, LQ, LT; eval_pqa_series_aux(N1,Nm,args,&LP,&LQ,<); @@ -83,25 +87,35 @@ static void eval_pqa_series_aux (uintL N1, uintL N2, } } -static void eval_pqsa_series_aux (uintL N1, uintL N2, - const cl_pqa_series& args, - cl_I* P, cl_I* Q, uintL* QS, cl_I* T) +template<> +const cl_LF eval_rational_series (uintC N, const cl_pqa_series& args, uintC len) +{ + if (N==0) + return cl_I_to_LF(0,len); + var cl_I Q, T; + eval_pqa_series_aux(0,N,args,NULL,&Q,&T); + return cl_I_to_LF(T,len) / cl_I_to_LF(Q,len); +} + +static void eval_pqsa_series_aux (uintC N1, uintC N2, + const cl_pqa_series& args, const uintC* qsv, + cl_I* P, cl_I* Q, uintC* QS, cl_I* T) { switch (N2 - N1) { case 0: - cl_abort(); break; + throw runtime_exception(); break; case 1: if (P) { *P = args.pv[N1]; } *Q = args.qv[N1]; - *QS = args.qsv[N1]; + *QS = qsv[N1]; *T = args.av[N1] * args.pv[N1]; break; case 2: { var cl_I p01 = args.pv[N1] * args.pv[N1+1]; if (P) { *P = p01; } *Q = args.qv[N1] * args.qv[N1+1]; - *QS = args.qsv[N1] + args.qsv[N1+1]; - *T = ((args.qv[N1+1] * args.av[N1] * args.pv[N1]) << args.qsv[N1+1]) + *QS = qsv[N1] + qsv[N1+1]; + *T = ((args.qv[N1+1] * args.av[N1] * args.pv[N1]) << qsv[N1+1]) + args.av[N1+1] * p01; break; } @@ -111,9 +125,9 @@ static void eval_pqsa_series_aux (uintL N1, uintL N2, if (P) { *P = p012; } var cl_I q12 = args.qv[N1+1] * args.qv[N1+2]; *Q = args.qv[N1] * q12; - *QS = args.qsv[N1] + args.qsv[N1+1] + args.qsv[N1+2]; - *T = ((q12 * args.av[N1] * args.pv[N1]) << (args.qsv[N1+1] + args.qsv[N1+2])) - + ((args.qv[N1+2] * args.av[N1+1] * p01) << args.qsv[N1+2]) + *QS = qsv[N1] + qsv[N1+1] + qsv[N1+2]; + *T = ((q12 * args.av[N1] * args.pv[N1]) << (qsv[N1+1] + qsv[N1+2])) + + ((args.qv[N1+2] * args.av[N1+1] * p01) << qsv[N1+2]) + args.av[N1+2] * p012; break; } @@ -125,23 +139,23 @@ static void eval_pqsa_series_aux (uintL N1, uintL N2, var cl_I q23 = args.qv[N1+2] * args.qv[N1+3]; var cl_I q123 = args.qv[N1+1] * q23; *Q = args.qv[N1] * q123; - *QS = args.qsv[N1] + args.qsv[N1+1] + args.qsv[N1+2] + args.qsv[N1+3]; - *T = ((((((q123 * args.av[N1] * args.pv[N1]) << args.qsv[N1+1]) - + q23 * args.av[N1+1] * p01) << args.qsv[N1+2]) - + args.qv[N1+3] * args.av[N1+2] * p012) << args.qsv[N1+3]) + *QS = qsv[N1] + qsv[N1+1] + qsv[N1+2] + qsv[N1+3]; + *T = ((((((q123 * args.av[N1] * args.pv[N1]) << qsv[N1+1]) + + q23 * args.av[N1+1] * p01) << qsv[N1+2]) + + args.qv[N1+3] * args.av[N1+2] * p012) << qsv[N1+3]) + args.av[N1+3] * p0123; break; } default: { - var uintL Nm = (N1+N2)/2; // midpoint + var uintC Nm = (N1+N2)/2; // midpoint // Compute left part. var cl_I LP, LQ, LT; - var uintL LQS; - eval_pqsa_series_aux(N1,Nm,args,&LP,&LQ,&LQS,<); + var uintC LQS; + eval_pqsa_series_aux(N1,Nm,args,qsv,&LP,&LQ,&LQS,<); // Compute right part. var cl_I RP, RQ, RT; - var uintL RQS; - eval_pqsa_series_aux(Nm,N2,args,(P?&RP:(cl_I*)0),&RQ,&RQS,&RT); + var uintC RQS; + eval_pqsa_series_aux(Nm,N2,args,qsv,(P?&RP:(cl_I*)0),&RQ,&RQS,&RT); // Put together partial results. if (P) { *P = LP*RP; } *Q = LQ*RQ; @@ -153,36 +167,201 @@ static void eval_pqsa_series_aux (uintL N1, uintL N2, } } -const cl_LF eval_rational_series (uintL N, const cl_pqa_series& args, uintC len) +template<> +const cl_LF eval_rational_series (uintC N, const cl_pqa_series& args, uintC len) +{ + if (N==0) + return cl_I_to_LF(0,len); + var cl_I Q, T; + // Precomputation of the shift counts: + // Split qv[n] into qv[n]*2^qsv[n]. + CL_ALLOCA_STACK; + var uintC* qsv = (uintC*) cl_alloca(N*sizeof(uintC)); + var cl_I* qp = args.qv; + var uintC* qsp = qsv; + for (var uintC n = 0; n < N; n++, qp++, qsp++) { + *qsp = pullout_shiftcount(*qp); + } + // Main computation. + var uintC QS; + eval_pqsa_series_aux(0,N,args,qsv,NULL,&Q,&QS,&T); + return cl_I_to_LF(T,len) / scale_float(cl_I_to_LF(Q,len),QS); +} + +static void eval_pqa_series_aux (uintC N1, uintC N2, + cl_pqa_series_stream& args, + cl_I* P, cl_I* Q, cl_I* T) +{ + switch (N2 - N1) { + case 0: + throw runtime_exception(); break; + case 1: { + var cl_pqa_series_term v0 = args.next(); // [N1] + if (P) { *P = v0.p; } + *Q = v0.q; + *T = v0.a * v0.p; + break; + } + case 2: { + var cl_pqa_series_term v0 = args.next(); // [N1] + var cl_pqa_series_term v1 = args.next(); // [N1+1] + var cl_I p01 = v0.p * v1.p; + if (P) { *P = p01; } + *Q = v0.q * v1.q; + *T = v1.q * v0.a * v0.p + + v1.a * p01; + break; + } + case 3: { + var cl_pqa_series_term v0 = args.next(); // [N1] + var cl_pqa_series_term v1 = args.next(); // [N1+1] + var cl_pqa_series_term v2 = args.next(); // [N1+2] + var cl_I p01 = v0.p * v1.p; + var cl_I p012 = p01 * v2.p; + if (P) { *P = p012; } + var cl_I q12 = v1.q * v2.q; + *Q = v0.q * q12; + *T = q12 * v0.a * v0.p + + v2.q * v1.a * p01 + + v2.a * p012; + break; + } + case 4: { + var cl_pqa_series_term v0 = args.next(); // [N1] + var cl_pqa_series_term v1 = args.next(); // [N1+1] + var cl_pqa_series_term v2 = args.next(); // [N1+2] + var cl_pqa_series_term v3 = args.next(); // [N1+3] + var cl_I p01 = v0.p * v1.p; + var cl_I p012 = p01 * v2.p; + var cl_I p0123 = p012 * v3.p; + if (P) { *P = p0123; } + var cl_I q23 = v2.q * v3.q; + var cl_I q123 = v1.q * q23; + *Q = v0.q * q123; + *T = q123 * v0.a * v0.p + + q23 * v1.a * p01 + + v3.q * v2.a * p012 + + v3.a * p0123; + break; + } + default: { + var uintC Nm = (N1+N2)/2; // midpoint + // Compute left part. + var cl_I LP, LQ, LT; + eval_pqa_series_aux(N1,Nm,args,&LP,&LQ,<); + // Compute right part. + var cl_I RP, RQ, RT; + eval_pqa_series_aux(Nm,N2,args,(P?&RP:(cl_I*)0),&RQ,&RT); + // Put together partial results. + if (P) { *P = LP*RP; } + *Q = LQ*RQ; + // S = LS + LP/LQ * RS, so T = RQ*LT + LP*RT. + *T = RQ*LT + LP*RT; + break; + } + } +} + +template<> +const cl_LF eval_rational_series (uintC N, cl_pqa_series_stream& args, uintC len) { if (N==0) return cl_I_to_LF(0,len); var cl_I Q, T; - if (!args.qsv) { - eval_pqa_series_aux(0,N,args,NULL,&Q,&T); - return cl_I_to_LF(T,len) / cl_I_to_LF(Q,len); - } else { - // Precomputation of the shift counts: - // Split qv[n] into qv[n]*2^qsv[n]. - { - var cl_I* qp = args.qv; - var uintL* qsp = args.qsv; - for (var uintL n = 0; n < N; n++, qp++, qsp++) { - // Pull out maximal power of 2 out of *qp = args.qv[n]. - var uintL qs = 0; - if (!zerop(*qp)) { - qs = ord2(*qp); - if (qs > 0) - *qp = *qp >> qs; - } - *qsp = qs; - } - } - // Main computation. - var uintL QS; - eval_pqsa_series_aux(0,N,args,NULL,&Q,&QS,&T); - return cl_I_to_LF(T,len) / scale_float(cl_I_to_LF(Q,len),QS); + eval_pqa_series_aux(0,N,args,NULL,&Q,&T); + return cl_I_to_LF(T,len) / cl_I_to_LF(Q,len); +} + +static void eval_pqa_series_aux (uintC N1, uintC N2, + cl_pqa_series_stream& args, + cl_R* P, cl_R* Q, cl_R* T, + uintC trunclen) +{ + switch (N2 - N1) { + case 0: + throw runtime_exception(); break; + case 1: { + var cl_pqa_series_term v0 = args.next(); // [N1] + if (P) { *P = v0.p; } + *Q = v0.q; + *T = v0.a * v0.p; + break; + } + case 2: { + var cl_pqa_series_term v0 = args.next(); // [N1] + var cl_pqa_series_term v1 = args.next(); // [N1+1] + var cl_I p01 = v0.p * v1.p; + if (P) { *P = p01; } + *Q = v0.q * v1.q; + *T = v1.q * v0.a * v0.p + + v1.a * p01; + break; + } + case 3: { + var cl_pqa_series_term v0 = args.next(); // [N1] + var cl_pqa_series_term v1 = args.next(); // [N1+1] + var cl_pqa_series_term v2 = args.next(); // [N1+2] + var cl_I p01 = v0.p * v1.p; + var cl_I p012 = p01 * v2.p; + if (P) { *P = p012; } + var cl_I q12 = v1.q * v2.q; + *Q = v0.q * q12; + *T = q12 * v0.a * v0.p + + v2.q * v1.a * p01 + + v2.a * p012; + break; + } + case 4: { + var cl_pqa_series_term v0 = args.next(); // [N1] + var cl_pqa_series_term v1 = args.next(); // [N1+1] + var cl_pqa_series_term v2 = args.next(); // [N1+2] + var cl_pqa_series_term v3 = args.next(); // [N1+3] + var cl_I p01 = v0.p * v1.p; + var cl_I p012 = p01 * v2.p; + var cl_I p0123 = p012 * v3.p; + if (P) { *P = p0123; } + var cl_I q23 = v2.q * v3.q; + var cl_I q123 = v1.q * q23; + *Q = v0.q * q123; + *T = q123 * v0.a * v0.p + + q23 * v1.a * p01 + + v3.q * v2.a * p012 + + v3.a * p0123; + break; + } + default: { + var uintC Nm = (N1+N2)/2; // midpoint + // Compute left part. + var cl_R LP, LQ, LT; + eval_pqa_series_aux(N1,Nm,args,&LP,&LQ,<,trunclen); + // Compute right part. + var cl_R RP, RQ, RT; + eval_pqa_series_aux(Nm,N2,args,(P?&RP:(cl_R*)0),&RQ,&RT,trunclen); + // Put together partial results. + if (P) { + *P = LP*RP; + truncate_precision(*P,trunclen); + } + *Q = LQ*RQ; + truncate_precision(*Q,trunclen); + // S = LS + LP/LQ * RS, so T = RQ*LT + LP*RT. + *T = RQ*LT + LP*RT; + truncate_precision(*T,trunclen); + break; + } } } + +template<> +const cl_LF eval_rational_series (uintC N, cl_pqa_series_stream& args, uintC len, uintC trunclen) +{ + if (N==0) + return cl_I_to_LF(0,len); + var cl_R Q, T; + eval_pqa_series_aux(0,N,args,NULL,&Q,&T,trunclen); + return cl_R_to_LF(T,len) / cl_R_to_LF(Q,len); +} // Bit complexity (if p(n), q(n), a(n), b(n) have length O(log(n))): // O(log(N)^2*M(N)). + +} // namespace cln