File Coverage

real.c
Criterion Covered Total %
statement 253 279 90.6
branch 161 242 66.5
condition n/a
subroutine n/a
pod n/a
total 414 521 79.4


line stmt bran cond sub pod time code
1             #include
2             #include
3             #include
4              
5             #define FUNC_log2floor 1
6             #include "ptypes.h"
7             #include "sieve.h"
8             #include "util.h"
9             #include "real.h"
10             #include "mathl.h"
11              
12             /* 1) Naive FP summation
13             * 2) Kahan summation
14             * 3) Neumaier, also called KBN or "improved Kahan–Babuška algorithm"
15             * 4) Klein, also called KB2 or second-order Kahan-Babuška
16             */
17             #define SUM_TYPE_NORMAL 0
18             #define SUM_TYPE_KAHAN 0
19             #define SUM_TYPE_NEUMAIER 1
20             #define SUM_TYPE_KLEIN 0
21              
22             #if SUM_TYPE_NORMAL
23             #define SUM_INIT(s) LNV s = 0.0;
24             #define SUM_ADD(s, term) s = s + (term);
25             #define SUM_FINAL(s) s
26             #endif
27             #if SUM_TYPE_KAHAN
28             #define SUM_INIT(s) \
29             LNV s ## _y, s ## _t; \
30             LNV s ## _c = 0.0; \
31             LNV s = 0.0;
32             #define SUM_ADD(s, term) \
33             do { \
34             s ## _y = (term) - s ## _c; \
35             s ## _t = s + s ## _y; \
36             s ## _c = (s ## _t - s) - s ## _y; \
37             s = s ## _t; \
38             } while (0)
39             #define SUM_FINAL(s) s
40             #endif
41             #if SUM_TYPE_NEUMAIER
42             #define SUM_INIT(s) \
43             LNV s ## _c = 0.0; \
44             LNV s = 0.0;
45             #define SUM_ADD(s, term) \
46             do { \
47             LNV _term = term; \
48             LNV _t = s + _term; \
49             if ( fabslnv(s) >= fabslnv(_term) ) \
50             s ## _c += (s - _t) + _term; \
51             else \
52             s ## _c += (_term - _t) + s; \
53             s = _t; \
54             } while (0)
55             #define SUM_FINAL(s) (s + s ## _c)
56             #endif
57             #if SUM_TYPE_KLEIN
58             #define SUM_INIT(s) \
59             LNV s ## _cs = 0.0; \
60             LNV s ## _ccs = 0.0; \
61             LNV s = 0.0;
62             #define SUM_ADD(s, term) \
63             do { \
64             LNV _term = term; \
65             LNV _c, _cc, _t = s + _term; \
66             if ( fabslnv(s) >= fabslnv(_term) ) \
67             _c = (s - _t) + _term; \
68             else \
69             _c = (_term - _t) + s; \
70             s = _t; \
71             _t = s ## _cs + _c; \
72             if ( fabslnv(s ## _cs) >= fabslnv(_c) ) \
73             _cc = (s ## _cs - _t) + _c; \
74             else \
75             _cc = (_c - _t) + s ## _cs; \
76             s ## _cs = _t; \
77             s ## _ccs += _cc; \
78             } while (0)
79             #define SUM_FINAL(s) (s + s ## _cs + s ## _ccs)
80             #endif
81              
82              
83             static const unsigned short primes_tiny[] =
84             {0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,
85             101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,
86             193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,
87             293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,
88             409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503};
89             #define NPRIMES_TINY (sizeof(primes_tiny)/sizeof(primes_tiny[0]))
90              
91              
92             /******************************************************************************/
93             /* REAL FUNCTIONS (EI,LI,etc.) */
94             /******************************************************************************/
95              
96             /*
97             * See:
98             * "Multiple-Precision Exponential Integral and Related Functions"
99             * by David M. Smith
100             * "On the Evaluation of the Complex-Valued Exponential Integral"
101             * by Vincent Pegoraro and Philipp Slusallek
102             * "Numerical Recipes" 3rd edition
103             * by William H. Press et al.
104             * "Rational Chevyshev Approximations for the Exponential Integral E_1(x)"
105             * by W. J. Cody and Henry C. Thacher, Jr.
106             * "High-precision Computation of Uniform Asymptotic Expansions for Special Functions"
107             * by Guillermo Navas-Palencia (2019)
108             *
109             * Any mistakes here are mine. This code has not been rigorously verified.
110             * Alternates: Navas-Palencia, Boost, MPFR, Pari/GP, Arb.
111             *
112             * We are trying to get close to maximum precision for all x with double, long
113             * double, and quadmath. Hence the rational Chebyshev approximations should
114             * not be used with quadmath (unless they are are modified).
115             *
116             * Performance, i7-6700HQ, 2.6GHz, 1e-9 to 1000 step 0.001
117             * range x > 0:
118             * 0.22 microseconds, NV = double max rel error 1.4e-14
119             * 0.19 microseconds, NV = long double max rel error 4.3e-17
120             * 18.97 microseconds, NV = quad max rel error 4.4e-32
121             * range x < 0:
122             * 0.18 microseconds, NV = double max rel error 1.4e-14
123             * 0.15 microseconds, NV = long double max rel error 1.2e-17
124             * 9.31 microseconds, NV = quad max rel error 1.7e-32
125             *
126             * The maximum error is near the root 0.3725074...
127             * The relative error profile for double precision is essentially identical
128             * to the Navas-Palencia expintei(x) function.
129             * Using long double on x86 improves the results with no time penalty.
130             * Using quadmath gives improved results at a substantial time penalty.
131             */
132              
133             static LNV const euler_mascheroni = LNVCONST(0.57721566490153286060651209008240243104215933593992);
134             static LNV const li2 = LNVCONST(1.045163780117492784844588889194613136522615578151);
135              
136             /* Rational Chebyshev approximation (Cody, Thacher), good for -1 < x < 0 */
137 5           static LNV _ei_chebyshev_neg(const LNV x) {
138             static const LNV C6p[7] = { LNVCONST(-148151.02102575750838086),
139             LNVCONST( 150260.59476436982420737),
140             LNVCONST( 89904.972007457256553251),
141             LNVCONST( 15924.175980637303639884),
142             LNVCONST( 2150.0672908092918123209),
143             LNVCONST( 116.69552669734461083368),
144             LNVCONST( 5.0196785185439843791020) };
145             static const LNV C6q[7] = { LNVCONST( 256664.93484897117319268),
146             LNVCONST( 184340.70063353677359298),
147             LNVCONST( 52440.529172056355429883),
148             LNVCONST( 8125.8035174768735759866),
149             LNVCONST( 750.43163907103936624165),
150             LNVCONST( 40.205465640027706061433),
151             LNVCONST( 1.0000000000000000000000) };
152 5           LNV sumn = C6p[0]-x*(C6p[1]-x*(C6p[2]-x*(C6p[3]-x*(C6p[4]-x*(C6p[5]-x*C6p[6])))));
153 5           LNV sumd = C6q[0]-x*(C6q[1]-x*(C6q[2]-x*(C6q[3]-x*(C6q[4]-x*(C6q[5]-x*C6q[6])))));
154 5           return loglnv(-x) - sumn/sumd;
155             }
156             /* Cody / Thacher rational Chebyshev for x > 24 */
157 1           static LNV _ei_chebyshev_pos24(const LNV x) {
158             static const LNV P2[10] = {
159             LNVCONST( 1.75338801265465972390E02),
160             LNVCONST(-2.23127670777632409550E02),
161             LNVCONST(-1.81949664929868906455E01),
162             LNVCONST(-2.79798528624305389340E01),
163             LNVCONST(-7.63147701620253630855E00),
164             LNVCONST(-1.52856623636929636839E01),
165             LNVCONST(-7.06810977895029358836E00),
166             LNVCONST(-5.00006640413131002475E00),
167             LNVCONST(-3.00000000320981265753E00),
168             LNVCONST( 1.00000000000000485503E00) };
169             static const LNV Q2[9] = {
170             LNVCONST( 3.97845977167414720840E04),
171             LNVCONST( 3.97277109100414518365E00),
172             LNVCONST( 1.37790390235747998793E02),
173             LNVCONST( 1.17179220502086455287E02),
174             LNVCONST( 7.04831847180424675988E01),
175             LNVCONST(-1.20187763547154743238E01),
176             LNVCONST(-7.99243595776339741065E00),
177             LNVCONST(-2.99999894040324959612E00),
178             LNVCONST( 1.99999999999048104167E00) };
179 1           LNV invx = LNV_ONE / x, frac = 0.0;
180             uint32_t n;
181 10 100         for (n = 0; n <= 8; n++)
182 9           frac = Q2[n] / (P2[n] + x + frac);
183 1           frac += P2[9];
184 1           return explnv(x) * (invx + invx*invx*frac);
185             }
186             #if 0
187             /* Continued fraction, good for x < -1 */
188             static LNV _ei_cfrac_neg(const LNV x) {
189             LNV lc = 0, ld = LNV_ONE / (LNV_ONE - x);
190             LNV val = ld * (-explnv(x));
191             uint32_t n;
192             for (n = 1; n <= 20000; n++) {
193             LNV old, t, n2 = n * n;
194             t = (LNV)(2*n + 1) - x;
195             lc = LNV_ONE / (t - n2 * lc);
196             ld = LNV_ONE / (t - n2 * ld);
197             old = val;
198             val *= ld/lc;
199             if ( fabslnv(val-old) <= LNV_EPSILON*fabslnv(val) )
200             break;
201             }
202             return val;
203             }
204             #endif
205             /* eint_v using Laguerre series, Navas-Palencia (2019). */
206 1           static LNV _eintv_laguerre_series(const LNV v, const LNV x) {
207 1           LNV L_k = 1.0, L_k1 = x + v;
208 1           LNV q, r, u = LNV_ONE, d = LNV_ONE;
209             uint32_t k;
210 1           SUM_INIT(sum);
211 1 50         SUM_ADD(sum, (LNV_ONE/L_k1));
212 20 50         for (k = 1; k < 500; k++) {
213 20           u *= v + k - 1;
214 20           d *= 1 + k;
215 20           q = L_k1 * (x + 2*k + v) / (k + 1) - L_k * (k + v - 1) / (k + 1);
216 20           r = u / (d * (q * L_k1));
217 20 50         SUM_ADD(sum, r);
218 20           L_k = L_k1;
219 20           L_k1 = q;
220 20 100         if (fabslnv(r) < 0.1 * LNV_EPSILON)
221 1           break;
222             }
223 1           return SUM_FINAL(sum) * explnv(-x);
224             }
225             /* Convergent series for small negative x through medium positive x */
226 131           static LNV _ei_series_convergent(LNV const x) {
227 131           LNV term, fact_n = x;
228             uint32_t n;
229 131           SUM_INIT(sum);
230 8704 50         for (n = 2; n <= 400; n++) {
231 8704           LNV invn = LNV_ONE / n;
232 8704           fact_n *= (LNV)x * invn;
233 8704           term = fact_n * invn;
234 8704 100         SUM_ADD(sum, term);
235             /* printf("C after adding %.20Lf, val = %.20Lf\n", term, SUM_FINAL(sum)); */
236 8704 100         if (fabslnv(term) < LNV_EPSILON*fabslnv(SUM_FINAL(sum))) break;
237             }
238 131 100         SUM_ADD(sum, euler_mascheroni);
239 131 50         SUM_ADD(sum, loglnv(fabslnv(x)));
240 131 100         SUM_ADD(sum, x);
241 131           return SUM_FINAL(sum);
242             }
243             /* Asymptotic divergent series, for large positive x */
244 0           static LNV _ei_series_divergent(LNV const x) {
245 0           LNV invx = LNV_ONE / x, term = invx;
246             unsigned int n;
247 0           SUM_INIT(sum);
248 0 0         for (n = 2; n <= 400; n++) {
249 0           LNV last_term = term;
250 0           term = term * ( (LNV)n * invx );
251 0 0         if (term < LNV_EPSILON*SUM_FINAL(sum)) break;
252 0 0         if (term < last_term) {
253 0 0         SUM_ADD(sum, term);
254             /* printf("A after adding %.20llf, sum = %.20llf\n", term, SUM_FINAL(sum)); */
255             } else {
256 0 0         SUM_ADD(sum, (-last_term/1.07) );
257             /* printf("A after adding %.20llf, sum = %.20llf\n", -last_term/1.07, SUM_FINAL(sum)); */
258 0           break;
259             }
260             }
261 0 0         SUM_ADD(sum, invx);
262 0 0         SUM_ADD(sum, LNV_ONE);
263 0           return explnv(x) * SUM_FINAL(sum) * invx;
264             }
265              
266 138           NV Ei(NV x) {
267 138           bool nv_is_quad = LNV_IS_QUAD; /* make C2X happy */
268 138 50         if (x == 0) croak("Invalid input to ExponentialIntegral: x must be != 0");
269             /* Protect against messed up rounding modes */
270 138 50         if (x >= 12000) return INFINITY;
271 138 50         if (x <= -12000) return 0;
272              
273 138 100         if (x < 0) {
274 6 100         if (x >= -1.0 && !nv_is_quad) return _ei_chebyshev_neg(x);
    50          
275 1 50         else if (x < -0.80) return -_eintv_laguerre_series(1, -x);
276 0           else return _ei_series_convergent(x);
277             } else {
278 132 100         if (x < (-2 * loglnv(LNV_EPSILON))) return _ei_series_convergent(x);
279 1 50         if (x >= 24 && (!nv_is_quad || x <= 43.2)) return _ei_chebyshev_pos24(x);
    50          
    0          
280 0           else return _ei_series_divergent(x);
281             }
282             }
283              
284 886           NV Li(NV x) {
285 886 50         if (x == 0) return 0;
286 886 50         if (x == 1) return -INFINITY;
287 886 50         if (x == 2) return li2;
288 886 50         if (x < 0) croak("Invalid input to LogarithmicIntegral: x must be >= 0");
289 886 50         if (x >= NV_MAX) return INFINITY;
290              
291             /* Calculate directly using Ramanujan's series. */
292 886 50         if (x > 1) {
293 886           const LNV logx = loglnv(x);
294 886           LNV sum = 0, inner_sum = 0, old_sum, factorial = 1, power2 = 1;
295 886           LNV q, p = -1;
296 886           int k = 0, n = 0;
297              
298 34116 50         for (n = 1, k = 0; n < 200; n++) {
299 34116           factorial *= n;
300 34116           p *= -logx;
301 34116           q = factorial * power2;
302 34116           power2 *= 2;
303 51403 100         for (; k <= (n - 1) / 2; k++)
304 17287           inner_sum += LNV_ONE / (2 * k + 1);
305 34116           old_sum = sum;
306 34116           sum += (p / q) * inner_sum;
307 34116 100         if (fabslnv(sum - old_sum) <= LNV_EPSILON) break;
308             }
309 886           return euler_mascheroni + loglnv(logx) + sqrtlnv(x) * sum;
310             }
311              
312 0           return Ei(loglnv(x));
313             }
314              
315 88           long double ld_inverse_li(long double lx) {
316             int i;
317 88           long double t, term, old_term = 0;
318             /* Iterate Halley's method until error grows. */
319 88 50         t = (lx <= 2) ? 2 : lx * logl(lx);
320 400 100         for (i = 0; i < 4; i++) {
321 352           long double dn = Li(t) - lx;
322 352           term = dn*logl(t) / (1.0L + dn/(2*t));
323 352 100         if (i > 0 && fabsl(term) >= fabsl(old_term)) { t -= term/4; break; }
    100          
324 312           old_term = term;
325 312           t -= term;
326             }
327 88           return t;
328             }
329              
330 87           UV inverse_li(UV x) {
331             UV r, i;
332 87           long double lx = (long double) x;
333              
334 87 100         if (x <= 2) return x + (x > 0);
335 84           r = (UV) ceill( ld_inverse_li(lx) );
336             /* Meet our more stringent goal of an exact answer. */
337 84 50         i = (x > 4e16) ? 2048 : 128;
338 84 50         if (Li(r-1) >= lx) {
339 0 0         while (Li(r-i) >= lx) r -= i;
340 0 0         for (i = i/2; i > 0; i /= 2)
341 0 0         if (Li(r-i) >= lx) r -= i;
342 84 50         } else if (Li(r) < lx) {
343 0 0         while (Li(r+i-1) < lx) r += i;
344 0 0         for (i = i/2; i > 0; i /= 2)
345 0 0         if (Li(r+i-1) < lx) r += i;
346             }
347 84           return r;
348             }
349              
350 23           static long double ld_inverse_R(long double lx) {
351             int i;
352 23           long double t, dn, term, old_term = 0;
353              
354             /* Rough estimate */
355 23 50         if (lx <= 3.5) {
356 0           t = lx + 2.24*(lx-1)/2;
357             } else {
358 23           t = lx * logl(lx);
359 23 50         if (lx < 50) { t *= 1.2; }
360 23 100         else if (lx < 1000) { t *= 1.15; }
361             else { /* use inverse Li (one iteration) for first inverse R approx */
362 22           dn = Li(t) - lx;
363 22           term = dn * logl(t) / (1.0L + dn/(2*t));
364 22           t -= term;
365             }
366             }
367             /* Iterate 1-n rounds of Halley, usually only 3 needed. */
368 143 50         for (i = 0; i < 100; i++) {
369 143           dn = RiemannR(t, 1e-12) - lx;
370             #if 1 /* Use f(t) = li(t) for derivatives */
371 143           term = dn * logl(t) / (1.0L + dn/(2*t));
372             #else /* Use f(t) = li(t) - li(sqrt(t))/2 for derivatives */
373             long double logt = logl(t);
374             long double sqrtt = sqrtl(t);
375             long double FA = 2 * sqrtt * logt;
376             long double FB = 2 * sqrtt - 1;
377             long double ifz = FA / FB;
378             long double iffz = (logt - 2*FB) / (2 * sqrtt * FA * FA * FA * FA);
379             term = dn * ifz * (1.0L - dn * iffz);
380             #endif
381 143 100         if (i > 0 && fabsl(term) >= fabsl(old_term)) { t -= term/4; break; }
    100          
382 120           old_term = term;
383 120           t -= term;
384             }
385 23           return t;
386             }
387              
388 23           UV inverse_R(UV x) {
389 23 50         if (x < 2) return x + (x > 0);
390 23           return (UV) ceill( ld_inverse_R( (long double) x) );
391             }
392              
393              
394             /*
395             * Storing the first 10-20 Zeta values makes sense. Past that it is purely
396             * to avoid making the call to generate them ourselves. We could cache the
397             * calculated values. These all have 1 subtracted from them. */
398             static const long double riemann_zeta_table[] = {
399             0.6449340668482264364724151666460251892L, /* zeta(2) */
400             0.2020569031595942853997381615114499908L,
401             0.0823232337111381915160036965411679028L,
402             0.0369277551433699263313654864570341681L,
403             0.0173430619844491397145179297909205279L,
404             0.0083492773819228268397975498497967596L,
405             0.0040773561979443393786852385086524653L,
406             0.0020083928260822144178527692324120605L,
407             0.0009945751278180853371459589003190170L,
408             0.0004941886041194645587022825264699365L,
409             0.0002460865533080482986379980477396710L,
410             0.0001227133475784891467518365263573957L,
411             0.0000612481350587048292585451051353337L,
412             0.0000305882363070204935517285106450626L,
413             0.0000152822594086518717325714876367220L,
414             0.0000076371976378997622736002935630292L, /* zeta(17) Past here all we're */
415             0.0000038172932649998398564616446219397L, /* zeta(18) getting is speed. */
416             0.0000019082127165539389256569577951013L,
417             0.0000009539620338727961131520386834493L,
418             0.0000004769329867878064631167196043730L,
419             0.0000002384505027277329900036481867530L,
420             0.0000001192199259653110730677887188823L,
421             0.0000000596081890512594796124402079358L,
422             0.0000000298035035146522801860637050694L,
423             0.0000000149015548283650412346585066307L,
424             0.0000000074507117898354294919810041706L,
425             0.0000000037253340247884570548192040184L,
426             0.0000000018626597235130490064039099454L,
427             0.0000000009313274324196681828717647350L,
428             0.0000000004656629065033784072989233251L,
429             0.0000000002328311833676505492001455976L,
430             0.0000000001164155017270051977592973835L,
431             0.0000000000582077208790270088924368599L,
432             0.0000000000291038504449709968692942523L,
433             0.0000000000145519218910419842359296322L,
434             0.0000000000072759598350574810145208690L,
435             0.0000000000036379795473786511902372363L,
436             0.0000000000018189896503070659475848321L,
437             0.0000000000009094947840263889282533118L,
438             0.0000000000004547473783042154026799112L,
439             0.0000000000002273736845824652515226821L,
440             0.0000000000001136868407680227849349105L,
441             0.0000000000000568434198762758560927718L,
442             0.0000000000000284217097688930185545507L,
443             0.0000000000000142108548280316067698343L,
444             0.00000000000000710542739521085271287735L,
445             0.00000000000000355271369133711367329847L,
446             0.00000000000000177635684357912032747335L,
447             0.000000000000000888178421093081590309609L,
448             0.000000000000000444089210314381336419777L,
449             0.000000000000000222044605079804198399932L,
450             0.000000000000000111022302514106613372055L,
451             0.0000000000000000555111512484548124372374L,
452             0.0000000000000000277555756213612417258163L,
453             0.0000000000000000138777878097252327628391L,
454             };
455             #define NPRECALC_ZETA (sizeof(riemann_zeta_table)/sizeof(riemann_zeta_table[0]))
456              
457             /* Riemann Zeta on the real line, with 1 subtracted.
458             * Compare to Math::Cephes zetac. Also zeta with q=1 and subtracting 1.
459             *
460             * The Cephes zeta function uses a series (2k)!/B_2k which converges rapidly
461             * and has a very wide range of values. We use it here for some values.
462             *
463             * Note: Calculations here are done on long doubles and we try to generate as
464             * much accuracy as possible. They will get returned to Perl as an NV,
465             * which is typically a 64-bit double with 15 digits.
466             *
467             * For values 0.5 to 5, this code uses the rational Chebyshev approximation
468             * from Cody and Thacher. This method is extraordinarily fast and very
469             * accurate over its range (slightly better than Cephes for most values). If
470             * we had quad floats, we could use the 9-term polynomial.
471             */
472 3916           long double ld_riemann_zeta(long double x) {
473             int i;
474              
475 3916 50         if (x < 0) croak("Invalid input to RiemannZeta: x must be >= 0");
476 3916 50         if (x == 1) return INFINITY;
477              
478 3916 100         if (x == (unsigned int)x) {
479 3912           int k = x - 2;
480 3912 50         if ((k >= 0) && (k < (int)NPRECALC_ZETA))
    100          
481 9           return riemann_zeta_table[k];
482             }
483              
484             /* Cody / Thacher rational Chebyshev approximation for small values */
485 3907 50         if (x >= 0.5 && x <= 5.0) {
    100          
486             static const long double C8p[9] = { 1.287168121482446392809e10L,
487             1.375396932037025111825e10L,
488             5.106655918364406103683e09L,
489             8.561471002433314862469e08L,
490             7.483618124380232984824e07L,
491             4.860106585461882511535e06L,
492             2.739574990221406087728e05L,
493             4.631710843183427123061e03L,
494             5.787581004096660659109e01L };
495             static const long double C8q[9] = { 2.574336242964846244667e10L,
496             5.938165648679590160003e09L,
497             9.006330373261233439089e08L,
498             8.042536634283289888587e07L,
499             5.609711759541920062814e06L,
500             2.247431202899137523543e05L,
501             7.574578909341537560115e03L,
502             -2.373835781373772623086e01L,
503             1.000000000000000000000L };
504 2           long double sumn = C8p[0]+x*(C8p[1]+x*(C8p[2]+x*(C8p[3]+x*(C8p[4]+x*(C8p[5]+x*(C8p[6]+x*(C8p[7]+x*C8p[8])))))));
505 2           long double sumd = C8q[0]+x*(C8q[1]+x*(C8q[2]+x*(C8q[3]+x*(C8q[4]+x*(C8q[5]+x*(C8q[6]+x*(C8q[7]+x*C8q[8])))))));
506 2           long double sum = (sumn - (x-1)*sumd) / ((x-1)*sumd);
507 2           return sum;
508             }
509              
510 3905 50         if (x > 17000.0)
511 0           return 0.0;
512              
513             #if 0
514             {
515             SUM_INIT(sum);
516             /* Simple defining series, works well. */
517             for (i = 5; i <= 1000000; i++) {
518             long double term = powl(i, -x);
519             SUM_ADD(sum, term);
520             if (term < LDBL_EPSILON*SUM_FINAL(sum)) break;
521             }
522             SUM_ADD(sum, powl(4, -x) );
523             SUM_ADD(sum, powl(3, -x) );
524             SUM_ADD(sum, powl(2, -x) );
525             return SUM_FINAL(sum);
526             }
527             #endif
528              
529             /* The 2n!/B_2k series used by the Cephes library. */
530             {
531             /* gp/pari:
532             * for(i=1,13,printf("%.38g\n",(2*i)!/bernreal(2*i)))
533             * MPU:
534             * use bignum;
535             * say +(factorial(2*$_)/bernreal(2*$_))->bround(38) for 1..13;
536             */
537             static const long double A[] = {
538             12.0L,
539             -720.0L,
540             30240.0L,
541             -1209600.0L,
542             47900160.0L,
543             -1892437580.3183791606367583212735166425L,
544             74724249600.0L,
545             -2950130727918.1642244954382084600497650L,
546             116467828143500.67248729113000661089201L,
547             -4597978722407472.6105457273596737891656L,
548             181521054019435467.73425331153534235290L,
549             -7166165256175667011.3346447367083352775L,
550             282908877253042996618.18640556532523927L,
551             };
552             long double a, b, s, t;
553 3905           const long double w = 10.0;
554 3905           s = 0.0;
555 3905           b = 0.0;
556 12909 100         for (i = 2; i < 11; i++) {
557 12907           b = powl( i, -x );
558 12907           s += b;
559 12907 100         if (fabsl(b) < fabsl(LDBL_EPSILON * s))
560 3903           return s;
561             }
562 2           s = s + b*w/(x-1.0) - 0.5 * b;
563 2           a = 1.0;
564 19 50         for (i = 0; i < 13; i++) {
565 19           long double k = 2*i;
566 19           a *= x + k;
567 19           b /= w;
568 19           t = a*b/A[i];
569 19           s = s + t;
570 19 100         if (fabsl(t) < fabsl(LDBL_EPSILON * s))
571 2           break;
572 17           a *= x + k + 1.0;
573 17           b /= w;
574             }
575 2           return s;
576             }
577             }
578              
579 366           long double RiemannR(long double x, long double eps) {
580             long double part_term, term, flogx, ki, old_sum;
581             unsigned int k;
582 366           SUM_INIT(sum);
583              
584 366 50         if (x <= 0) croak("Invalid input to RiemannR: x must be > 0");
585 366 100         if (eps < LDBL_EPSILON) eps = LDBL_EPSILON;
586              
587 366 100         if (x > 1e19) {
588 2           const signed char* amob = range_moebius(0, 100);
589 2 50         SUM_ADD(sum, Li(x));
590 132 50         for (k = 2; k <= 100; k++) {
591 132 100         if (amob[k] == 0) continue;
592 82           ki = 1.0L / (long double) k;
593 82           part_term = powl(x,ki);
594 82 50         if (part_term > LDBL_MAX) return INFINITY;
595 82           term = amob[k] * ki * Li(part_term);
596 82           old_sum = SUM_FINAL(sum);
597 82 50         SUM_ADD(sum, term);
598 82 100         if (fabslnv(SUM_FINAL(sum) - old_sum) <= eps) break;
599             }
600 2           Safefree(amob);
601 2           return SUM_FINAL(sum);
602             }
603              
604 364 50         SUM_ADD(sum, 1.0);
605 364           flogx = logl(x);
606 364           part_term = 1;
607              
608 23081 50         for (k = 1; k <= 10000; k++) {
609 23081 100         ki = (k-1 < NPRECALC_ZETA) ? riemann_zeta_table[k-1] : ld_riemann_zeta(k+1);
610 23081           part_term *= flogx / k;
611 23081           term = part_term / (k + k * ki);
612 23081           old_sum = SUM_FINAL(sum);
613 23081 100         SUM_ADD(sum, term);
614             /* printf("R %5d after adding %.18Lg, sum = %.19Lg (%Lg)\n", k, term, sum, fabsl(sum-old_sum)); */
615 23081 100         if (fabslnv(SUM_FINAL(sum) - old_sum) <= eps) break;
616             }
617              
618 364           return SUM_FINAL(sum);
619             }
620              
621             /* Options for LambertW initial approximation:
622             *
623             * - Four regions, we used before:
624             * Pade(3,2), Winitzki 2003, Vargas 2013, Corless 1993
625             * Has issues near -1/e but ok around zero.
626             *
627             * - Iacono and Boyd (2017). Very simple function over whole range.
628             * Doesn't work right very near -1/e and around zero.
629             *
630             * - Vazquez-Leal et al. (2019). Divides into four regions, power
631             * series for each. Great results. Also has issues near -1/e and zero.
632             *
633             * We use known solutions for near -1/e and around zero. See Fukushima (2013)
634             * and Johannson (2017,2020) for lots of discussion and solutions.
635             * Use Vazquez-Leal (PSEM Approximations) for the rest.
636             */
637 8           static long double _lambertw_approx(long double x) {
638             long double w, k1, k2, k3;
639              
640 8 100         if (x < -0.312) {
641             /* Use Puiseux series, e.g. Verberic 2009, Boost, Johannson (2020). */
642             /* Near the branch point. See Fukushima (2013) section 2.5. */
643 1           k2 = 2.0L * (1.0L + 2.7182818284590452353603L * x);
644 1 50         if (k2 <= 0) return -1.0L + 1*LDBL_EPSILON;
645 1           k1 = sqrtl(k2);
646 1           w = -1.0L + (1.0L + (-1.0L/3.0L + (11.0L/72.0L + (-43.0L/540.0L + (769.0L/17280.0L + (-221.0L/8505.0L + (680863.0L/43545600.0L + (-1963.0L/204120.0L + 226287557.0L/37623398400.0L
647 1           * k1) * k1) * k1) * k1) * k1) * k1) * k1) * k1) * k1;
648              
649 7 50         } else if (x > -0.14 && x < 0.085) {
    100          
650             /* Around zero. See Fukushima (2013) section 2.6. */
651 1           w = (1.0L + (-1.0L + (3.0L/2.0L + (-8.0L/3.0L + (125.0L/24.0L + (-54.0L/5.0L + (16807.0L/720.0L + (-16384.0L/315.0L + 531441.0L/4480.0L
652 1           * x) * x) * x) * x) * x) * x) * x) * x) * x;
653              
654 6 100         } else if (x < 1) {
655             /* This and the rest from Vazquez-Leal et al. (2019). */
656 1           k1 = sqrtl(1.0L + 2.7182818284590452353603L * x);
657 1           k2 = 0.33333333333333333333333L + 0.70710678118654752440084L / k1 - 0.058925565098878960366737L * k1 +
658 1           (x + 0.36787944117144L) * (0.050248489761611L + (0.11138904851051 + 0.040744556245195L * x) * x)
659 1           /
660 1           (1.0L + (2.7090878606183L + (1.5510922597820L + 0.095477712183841L * x) * x) * x);
661 1           w = -(k2-1)/k2;
662              
663 5 100         } else if (x < 40) {
664 2           k1 = 1.0L + (5.950065500550155L + (13.96586471370701L + (10.52192021050505L + (3.065294254265870L + 0.1204576876518760L * x) * x) * x) * x) * x;
665 2           w = 0.1600049638651493L * logl(k1);
666              
667 3 100         } else if (x < 20000) {
668 1           k1 = 1.0L + (-3.16866642511229e11L + (3.420439800038598e10L +
669 1           (-1.501433652432257e9L + (3.44887729947585e7L + (-4.453783741137856e5L +
670 1           (3257.926478908996L + (-10.82545259305382L + (0.6898058947898353e-1L +
671 1           0.4703653406071575e-4L * x) * x) * x) * x) * x) * x) * x) * x) * x;
672 1           w = 0.9898045358731312e-1L * logl(k1);
673              
674             } else {
675 2           k1 = 1.0L / (1.0L + logl(1.0L + x));
676 2           k2 = 1.0L / k1;
677 2           k3 = logl(k2);
678 2           w = k2-1-k3+(1+k3+(-1/2+(1/2)*k3*k3 +(-1/6+(-1+(-1/2+
679 2           (1/3) * k3) * k3) * k3) * k1) * k1) * k1;
680             }
681 8           return w;
682             }
683              
684 9           NV lambertw(NV x) {
685             long double w;
686             int i;
687              
688 9 50         if (x < -0.36787944117145L)
689 0           croak("Invalid input to LambertW: x must be >= -1/e");
690 9 100         if (x == 0.0L) return 0.0L;
691              
692             /* Estimate initial value */
693 8           w = _lambertw_approx(x);
694              
695             /* TODO: this section might not be best for quad precision */
696             /* If input is too small, return .99999.... */
697             /* if (w <= -1.0L) return -1.0L + LDBL_EPSILON; */
698             /* For very small inputs, don't iterate, return approx directly. */
699 8 100         if (x < -0.36768) return w;
700              
701             #if 0 /* Halley */
702             long double lastw = w;
703             for (i = 0; i < 100; i++) {
704             long double ew = expl(w);
705             long double wew = w * ew;
706             long double wewx = wew - x;
707             long double w1 = w + 1;
708             w = w - wewx / (ew * w1 - (w+2) * wewx/(2*w1));
709             if (w != 0.0L && fabsl((w-lastw)/w) <= 8*LDBL_EPSILON) break;
710             lastw = w;
711             }
712             #else /* Fritsch, see Veberic 2009. 1-2 iterations are enough. */
713 15 50         for (i = 0; i < 6 && w != 0.0L; i++) {
    50          
714 15           long double w1 = 1 + w;
715 15           long double zn = logl((long double)x/w) - w;
716 15           long double qn = 2 * w1 * (w1+(2.0L/3.0L)*zn);
717 15           long double en = (zn/w1) * (qn-zn)/(qn-2.0L*zn);
718             /* w *= 1.0L + en; if (fabsl(en) <= 16*LDBL_EPSILON) break; */
719 15           long double wen = w * en;
720 15 50         if (isnan(wen)) return 0;
721 15           w += wen;
722 15 100         if (fabsl(wen) <= 64*LDBL_EPSILON) break;
723             }
724             #endif
725              
726             #if LNV_IS_QUAD /* For quadmath, one high precision correction */
727             if (w != LNV_ZERO) {
728             LNV lw = w;
729             LNV w1 = LNV_ONE + lw;
730             LNV zn = loglnv((LNV)x/lw) - lw;
731             LNV qn = LNVCONST(2.0) * w1 * (w1+(LNVCONST(2.0)/LNVCONST(3.0))*zn);
732             LNV en = (zn/w1) * (qn-zn)/(qn-LNVCONST(2.0)*zn);
733             return lw + lw * en;
734             }
735             #endif
736              
737             /* With long double = 64-bit double, we have 15 digits precision
738             * near the branch point, and 16 over the rest of the range.
739             * With long double = x86 extended precision, we have over 17 digits
740             * over the entire range.
741             * Correcting to the exact LDBL_EPSILON does not improve this. */
742              
743 7           return w;
744             }
745              
746              
747             /******************************************************************************/
748             /* Chebyshev PSI / THETA */
749             /******************************************************************************/
750              
751 9           NV chebyshev_psi(UV n)
752             {
753             UV k;
754 9           SUM_INIT(sum);
755              
756 58 100         for (k = log2floor(n); k > 0; k--) {
    100          
757 49 100         SUM_ADD(sum, chebyshev_theta(rootint(n,k)));
758             }
759 9           return SUM_FINAL(sum);
760             }
761              
762             #if BITS_PER_WORD == 64
763             typedef struct {
764             UV n;
765             LNV theta;
766             } cheby_theta_t;
767             static const cheby_theta_t _cheby_theta[] = { /* >= quad math precision */
768             { UVCONST( 67108864),LNVCONST( 67100507.6357700963903836828562472350035880) },
769             { UVCONST( 100000000),LNVCONST( 99987730.0180220043832124342600487053812729) },
770             { UVCONST( 134217728),LNVCONST( 134204014.5735572091791081610859055728165544) },
771             { UVCONST( 268435456),LNVCONST( 268419741.6134308193112682817754501071404173) },
772             { UVCONST( 536870912),LNVCONST( 536842885.8045763840625719515011160692495056) },
773             { UVCONST( 1000000000),LNVCONST( 999968978.5775661447991262386023331863364793) },
774             { UVCONST( 1073741824),LNVCONST( 1073716064.8860663337617909073555831842945484) },
775             { UVCONST( 2147483648),LNVCONST( 2147432200.2475857676814950053003448716360822) },
776             { UVCONST( 4294967296),LNVCONST( 4294889489.1735446386752045191908417183337361) },
777             { UVCONST( 8589934592),LNVCONST( 8589863179.5654263491545135406516173629373070) },
778             { UVCONST( 10000000000),LNVCONST( 9999939830.6577573841592219954033850595228736) },
779             { UVCONST( 12884901888),LNVCONST( 12884796620.4324254952601520445848183460347362) },
780             { UVCONST( 17179869184),LNVCONST( 17179757715.9924077567777285147574707468995695) },
781             { UVCONST( 21474836480),LNVCONST( 21474693322.0998273969188369449626287713082943) },
782             { UVCONST( 25769803776),LNVCONST( 25769579799.3751535467593954636665656772211515) },
783             { UVCONST( 30064771072),LNVCONST( 30064545001.2305211029215168703433831598544454) },
784             { UVCONST( 34359738368),LNVCONST( 34359499180.0126643918259085362039638823175054) },
785             { UVCONST( 51539607552),LNVCONST( 51539356394.9531019037592855639826469993402730) },
786             { UVCONST( 68719476736),LNVCONST( 68719165213.6369838785284711480925219076501720) },
787             { UVCONST( 85899345920),LNVCONST( 85899083852.3471545629838432726841470626910905) },
788             { UVCONST( 100000000000),LNVCONST( 99999737653.1074446948519125729820679772770146) },
789             { UVCONST( 103079215104),LNVCONST(103079022007.113299711630969211422868856259124) },
790             { UVCONST( 120259084288),LNVCONST(120258614516.787336970535750737470005730125261) },
791             { UVCONST( 137438953472),LNVCONST(137438579206.444595884982301543904849253294539) },
792             { UVCONST( 171798691840),LNVCONST(171798276885.585945657918751085729734540334501) },
793             { UVCONST( 206158430208),LNVCONST(206158003808.160276853604927822609009916573462) },
794             { UVCONST( 240518168576),LNVCONST(240517893445.995868018331936763125264759516048) },
795             { UVCONST( 274877906944),LNVCONST(274877354651.045354829956619821889825596300686) },
796             { UVCONST( 309237645312),LNVCONST(309237050379.850690561796126460858271984023198) },
797             { UVCONST( 343597383680),LNVCONST(343596855806.595496630500062749631211394707114) },
798             { UVCONST( 377957122048),LNVCONST(377956498560.227794386327526022452943941537993) },
799             { UVCONST( 412316860416),LNVCONST(412316008796.349553568121442261222464590518293) },
800             { UVCONST( 446676598784),LNVCONST(446675972485.936512329625489223180824947531484) },
801             { UVCONST( 481036337152),LNVCONST(481035608287.572961376833237046440177624505864) },
802             { UVCONST( 515396075520),LNVCONST(515395302740.633513931333424447688399032397200) },
803             { UVCONST( 549755813888),LNVCONST(549755185085.539613556787409928561107952681488) },
804             { UVCONST( 584115552256),LNVCONST(584115015741.698143680148976236958207248900725) },
805             { UVCONST( 618475290624),LNVCONST(618474400071.621528348965919774195984612254220) },
806             { UVCONST( 652835028992),LNVCONST(652834230470.583317059774197550110194348469358) },
807             { UVCONST( 687194767360),LNVCONST(687193697328.927006867624832386534836384752774) },
808             { UVCONST( 721554505728),LNVCONST(721553211683.605313067593521060195071837766347) },
809             { UVCONST( 755914244096),LNVCONST(755913502349.878525212441903698096011352015192) },
810             { UVCONST( 790273982464),LNVCONST(790273042590.053075430445971969285969445183076) },
811             { UVCONST( 824633720832),LNVCONST(824633080997.428352876758261549475609957696369) },
812             { UVCONST( 858993459200),LNVCONST(858992716288.318498931165663742671579465316192) },
813             { UVCONST( 893353197568),LNVCONST(893352235882.851072417721659027263613727927680) },
814             { UVCONST( 927712935936),LNVCONST(927711881043.628817668337317445143018372892386) },
815             { UVCONST( 962072674304),LNVCONST(962071726126.508938539006575212272731584070786) },
816             { UVCONST( 996432412672),LNVCONST(996431411588.361462717402562171913706963939018) },
817             { UVCONST( 1099511627776),LNVCONST(1099510565082.05800550569923209414874779035972) },
818             { UVCONST( 1168231104512),LNVCONST(1168230478726.83399452743801182220790107593115) },
819             { UVCONST( 1236950581248),LNVCONST(1236949680081.02610603189530371762093291521116) },
820             { UVCONST( 1305670057984),LNVCONST(1305668780900.04255251887970870257110498423202) },
821             { UVCONST( 1374389534720),LNVCONST(1374388383792.63751003694755359184583212193880) },
822             { UVCONST( 1443109011456),LNVCONST(1443107961091.80955496949174183091839841371227) },
823             { UVCONST( 1511828488192),LNVCONST(1511827317611.91227277802426032456922797572429) },
824             { UVCONST( 1580547964928),LNVCONST(1580546753969.30607547506449941085747942395437) },
825             { UVCONST( 1649267441664),LNVCONST(1649265973878.75361554498682516738256005501353) },
826             { UVCONST( 1717986918400),LNVCONST(1717985403764.24562741452793071287954107946922) },
827             { UVCONST( 1786706395136),LNVCONST(1786704769212.04241689416220650800274263053933) },
828             { UVCONST( 1855425871872),LNVCONST(1855425013030.54920163513184322741954734357404) },
829             { UVCONST( 1924145348608),LNVCONST(1924143701943.02957992419280264060220278182021) },
830             { UVCONST( 1992864825344),LNVCONST(1992863373568.84039296068619447120308124302086) },
831             { UVCONST( 2061584302080),LNVCONST(2061583632335.91985095534685076604018573279204) },
832             { UVCONST( 2130303778816),LNVCONST(2113122935598.01727180199783433992649406589029) },
833             { UVCONST( 2199023255552),LNVCONST(2199021399611.18488312543276191461914978761981) },
834             { UVCONST( 2267742732288),LNVCONST(2267740947106.05038218811506263712808318234921) },
835             { UVCONST( 2336462209024),LNVCONST(2336460081480.34962633829077377680844065198307) },
836             { UVCONST( 2405181685760),LNVCONST(2405179969505.38642629423585641169740223940265) },
837             { UVCONST( 2473901162496),LNVCONST(2473899311193.37872375168104562948639924654178) },
838             { UVCONST( 2542620639232),LNVCONST(2542619362554.88893589220737167756411653816418) },
839             { UVCONST( 2611340115968),LNVCONST(2611338370515.94936514022501267847930999670553) },
840             { UVCONST( 2680059592704),LNVCONST(2680057722824.52981820001574883706268873541107) },
841             { UVCONST( 2748779069440),LNVCONST(2748777610452.18903407570165081726781627254885) },
842             { UVCONST( 2817498546176),LNVCONST(2817497017165.31924616507392971415494161401775) },
843             { UVCONST( 2886218022912),LNVCONST(2886216579432.32232322707222172612181994322081) },
844             { UVCONST( 2954937499648),LNVCONST(2954936100812.97301730406598982753121204977388) },
845             { UVCONST( 3023656976384),LNVCONST(3023654789503.82041452274471455184651411931920) },
846             { UVCONST( 3298534883328),LNVCONST(3298533215621.76606493931157388037915263658637) },
847             { UVCONST( 3573412790272),LNVCONST(3573411344351.74163523704886736624674718378131) },
848             { UVCONST( 3848290697216),LNVCONST(3848288415701.82534219216958446478503907262807) },
849             { UVCONST( 4123168604160),LNVCONST(4123166102085.86116301709394219323327831487542) },
850             { UVCONST( 4398046511104),LNVCONST(4398044965678.05143041707871320554940671182665) },
851             { UVCONST( 4672924418048),LNVCONST(4672922414672.04998927945349278916525727295687) },
852             { UVCONST( 4947802324992),LNVCONST(4947800056419.04384937181159608905993450182729) },
853             { UVCONST( 5222680231936),LNVCONST(5222678728087.69487334278665824384732845008859) },
854             { UVCONST( 5497558138880),LNVCONST(5497555766573.55159115560501595606332808978878) },
855             { UVCONST( 5772436045824),LNVCONST(5772433560746.27053256770924553245647027548204) },
856             { UVCONST( 6047313952768),LNVCONST(6047310750621.24497633828761530843255989494448) },
857             { UVCONST( 6322191859712),LNVCONST(6322189275338.39747421237532473168802646234745) },
858             { UVCONST( 6597069766656),LNVCONST(6579887620000.56226807898107616294821989189226) },
859             { UVCONST( 6871947673600),LNVCONST(6871945430474.61791600096091374271286154432006) },
860             { UVCONST( 7146825580544),LNVCONST(7146823258390.34361980709600216319269118247416) },
861             { UVCONST( 7421703487488),LNVCONST(7421700443390.35536080251964387835425662360121) },
862             { UVCONST( 7696581394432),LNVCONST(7696578975137.73249441643024336954233783264803) },
863             { UVCONST( 7971459301376),LNVCONST(7971457197928.90863708984184849978605273042512) },
864             { UVCONST( 8246337208320),LNVCONST(8246333982863.77146812177727648999195989358960) },
865             { UVCONST( 8521215115264),LNVCONST(8529802085075.55635100929751669785228592926043) },
866             { UVCONST( 8796093022208),LNVCONST(8796089836425.34909684634625258535266362465034) },
867             { UVCONST( 9345848836096),LNVCONST(9345845828116.77456046925508587313) },
868             { UVCONST( 9895604649984),LNVCONST(9895601077915.26821447819584407150) },
869             { UVCONST(10000000000000),LNVCONST(9999996988293.03419965318214160284) },
870             { UVCONST(15000000000000),LNVCONST(14999996482301.7098815115045166858) },
871             { UVCONST(20000000000000),LNVCONST(19999995126082.2286880312461318496) },
872             { UVCONST(25000000000000),LNVCONST(24999994219058.4086216020475916538) },
873             { UVCONST(30000000000000),LNVCONST(29999995531389.8454274046657200568) },
874             { UVCONST(35000000000000),LNVCONST(34999992921190.8049427456456479005) },
875             { UVCONST(40000000000000),LNVCONST(39999993533724.3168289589273168844) },
876             { UVCONST(45000000000000),LNVCONST(44999993567606.9795798378256194424) },
877             { UVCONST(50000000000000),LNVCONST(49999992543194.2636545758235373677) },
878             { UVCONST(55000000000000),LNVCONST(54999990847877.2435105757522625171) },
879             { UVCONST(60000000000000),LNVCONST(59999990297033.6261976055811111726) },
880             { UVCONST(65000000000000),LNVCONST(64999990861395.5522142429859245014) },
881             { UVCONST(70000000000000),LNVCONST(69999994316409.8717306521862685981) },
882             { UVCONST(75000000000000),LNVCONST(74999990126219.8344899338374090165) },
883             { UVCONST(80000000000000),LNVCONST(79999990160858.3042387288372250950) },
884             { UVCONST(85000000000000),LNVCONST(84999987096970.5915212896832780715) },
885             { UVCONST(90000000000000),LNVCONST(89999989501395.0738966599857919767) },
886             { UVCONST(95000000000000),LNVCONST(94999990785908.6672552042792168144) },
887             { UVCONST(100000000000000),LNVCONST(99999990573246.9785384070303475639) },
888             };
889             #define NCHEBY_VALS (sizeof(_cheby_theta)/sizeof(_cheby_theta[0]))
890             #endif
891              
892 59           NV chebyshev_theta(UV n)
893             {
894 59           uint16_t i = 0;
895             UV tp, startn, seg_base, seg_low, seg_high;
896             unsigned char* segment;
897             void* ctx;
898 59           LNV initial_sum, prod = LNV_ONE;
899 59           SUM_INIT(sum);
900              
901 59 100         if (n < 500) {
902 379 100         for (i = 1; (tp = primes_tiny[i]) <= n; i++) {
903 326 100         SUM_ADD(sum, loglnv(tp));
904             }
905 53           return SUM_FINAL(sum);
906             }
907              
908             #if defined NCHEBY_VALS
909 6 100         if (n >= _cheby_theta[0].n) {
910 1 50         for (i = 1; i < NCHEBY_VALS; i++)
911 1 50         if (n < _cheby_theta[i].n)
912 1           break;
913 1           startn = _cheby_theta[i-1].n;
914 1           initial_sum = _cheby_theta[i-1].theta;
915             } else
916             #endif
917             {
918 5 50         SUM_ADD(sum, loglnv(2*3*5*7*11*13));
919 5           startn = 17;
920 5           initial_sum = 0;
921             }
922              
923 6           ctx = start_segment_primes(startn, n, &segment);
924             #if 0
925             while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
926             START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high ) {
927             SUM_ADD(sum, loglnv(p));
928             } END_DO_FOR_EACH_SIEVE_PRIME
929             }
930             #else
931 16 100         while (next_segment_primes(ctx, &seg_base, &seg_low, &seg_high)) {
932 350117 50         START_DO_FOR_EACH_SIEVE_PRIME( segment, seg_base, seg_low, seg_high ) {
    100          
    100          
    100          
    100          
933 330048           prod *= (LNV) p;
934 330048 100         if (++i >= (LNV_IS_QUAD ? 64 : 8)) {
935 41254 100         SUM_ADD(sum, loglnv(prod));
936 41254           prod = LNV_ONE;
937 41254           i = 0;
938             }
939 20044           } END_DO_FOR_EACH_SIEVE_PRIME
940             }
941 6 50         if (prod > 1.0) { SUM_ADD(sum, loglnv(prod)); prod = LNV_ONE; }
    50          
942             #endif
943 6           end_segment_primes(ctx);
944              
945 6 100         if (initial_sum > 0) SUM_ADD(sum, initial_sum);
    50          
946 6           return SUM_FINAL(sum);
947             }
948              
949              
950             /******************************************************************************/
951             /* Other */
952             /******************************************************************************/
953              
954             #if 0
955             /* This is the de Bruijn approximation, not exact! */
956             static long double dickman_rho(long double u) {
957             int i;
958             long double zeta;
959              
960             if (u <= 1) return 1;
961             if (u <= 2) return 1-logl(u);
962              
963             /* Also see:
964             * Granville 2008 https://dms.umontreal.ca/~andrew/PDF/msrire.pdf
965             * Gorodetsky 2022 https://arxiv.org/pdf/2212.01949.pdf
966             * van Hoek 2019 https://studenttheses.uu.nl/bitstream/handle/20.500.12932/32867/Masterscriptie%20Bart%20van%20Hoek.pdf
967             */
968              
969             /* Calculate zeta. See Bach and Sorenson (2013) page 10 */
970             zeta = 2*(u-1);
971             for (i = 0; i < 7; i++) {
972             long double uz1 = 1 + u*zeta;
973             zeta = zeta - ( (zeta-logl(uz1))*uz1 ) / (uz1-u);
974             }
975             /* Alternately: zeta = -1/u - LambertW1(-exp(-1/u)/u) */
976              
977             return expl(-u*zeta+Ei(zeta)) / (zeta * sqrtl(2*3.1415926535*u));
978             }
979             #endif
980              
981