flexiblesusy is hosted by Hepforge, IPPP Durham
FlexibleSUSY
Li2.cpp
Go to the documentation of this file.
1// ====================================================================
2// This file is part of FlexibleSUSY.
3//
4// FlexibleSUSY is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published
6// by the Free Software Foundation, either version 3 of the License,
7// or (at your option) any later version.
8//
9// FlexibleSUSY is distributed in the hope that it will be useful, but
10// WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with FlexibleSUSY. If not, see
16// <http://www.gnu.org/licenses/>.
17// ====================================================================
18
19#include "Li2.hpp"
20#include "complex.hpp"
21#include <cfloat>
22#include <cmath>
23#include <limits>
24
25namespace flexiblesusy {
26
27namespace {
28
29 template <typename T, int N>
30 T horner(T x, const T (&c)[N]) noexcept
31 {
32 T p = c[N - 1];
33 for (int i = N - 2; i >= 0; --i) {
34 p = p*x + c[i];
35 }
36 return p;
37 }
38
39 template <int Nstart, typename T, int N>
40 Complex<T> horner(const Complex<T>& z, const T (&coeffs)[N]) noexcept
41 {
42 static_assert(0 <= Nstart && Nstart < N && N >= 2, "invalid array bounds");
43
44 const T r = z.re + z.re;
45 const T s = z.re * z.re + z.im * z.im;
46 T a = coeffs[N - 1], b = coeffs[N - 2];
47
48 for (int i = N - 3; i >= Nstart; --i) {
49 const T t = a;
50 a = b + r * a;
51 b = coeffs[i] - s * t;
52 }
53
54 return Complex<T>(z.re*a + b, z.im*a);
55 }
56
57} // anonymous namespace
58
68double Li2(double x) noexcept
69{
70 const double PI = 3.1415926535897932;
71 const double P[] = {
72 0.9999999999999999502e+0,
73 -2.6883926818565423430e+0,
74 2.6477222699473109692e+0,
75 -1.1538559607887416355e+0,
76 2.0886077795020607837e-1,
77 -1.0859777134152463084e-2
78 };
79 const double Q[] = {
80 1.0000000000000000000e+0,
81 -2.9383926818565635485e+0,
82 3.2712093293018635389e+0,
83 -1.7076702173954289421e+0,
84 4.1596017228400603836e-1,
85 -3.9801343754084482956e-2,
86 8.2743668974466659035e-4
87 };
88
89 double y = 0, r = 0, s = 1;
90
91 // transform to [0, 1/2]
92 if (x < -1) {
93 const double l = std::log(1 - x);
94 y = 1/(1 - x);
95 r = -PI*PI/6 + l*(0.5*l - std::log(-x));
96 s = 1;
97 } else if (x == -1) {
98 return -PI*PI/12;
99 } else if (x < 0) {
100 const double l = std::log1p(-x);
101 y = x/(x - 1);
102 r = -0.5*l*l;
103 s = -1;
104 } else if (x == 0) {
105 return 0;
106 } else if (x < 0.5) {
107 y = x;
108 r = 0;
109 s = 1;
110 } else if (x < 1) {
111 y = 1 - x;
112 r = PI*PI/6 - std::log(x)*std::log1p(-x);
113 s = -1;
114 } else if (x == 1) {
115 return PI*PI/6;
116 } else if (x < 2) {
117 const double l = std::log(x);
118 y = 1 - 1/x;
119 r = PI*PI/6 - l*(std::log(y) + 0.5*l);
120 s = 1;
121 } else {
122 const double l = std::log(x);
123 y = 1/x;
124 r = PI*PI/3 - 0.5*l*l;
125 s = -1;
126 }
127
128 const double y2 = y*y;
129 const double y4 = y2*y2;
130 const double p = P[0] + y * P[1] + y2 * (P[2] + y * P[3]) +
131 y4 * (P[4] + y * P[5]);
132 const double q = Q[0] + y * Q[1] + y2 * (Q[2] + y * Q[3]) +
133 y4 * (Q[4] + y * Q[5] + y2 * Q[6]);
134
135 return r + s*y*p/q;
136}
137
148long double Li2(long double x) noexcept
149{
150 const long double PI = 3.14159265358979323846264338327950288L;
151
152#if LDBL_DIG <= 18
153 const long double P[] = {
154 1.07061055633093042767673531395124630e+0L,
155 -5.25056559620492749887983310693176896e+0L,
156 1.03934845791141763662532570563508185e+1L,
157 -1.06275187429164237285280053453630651e+1L,
158 5.95754800847361224707276004888482457e+0L,
159 -1.78704147549824083632603474038547305e+0L,
160 2.56952343145676978700222949739349644e-1L,
161 -1.33237248124034497789318026957526440e-2L,
162 7.91217309833196694976662068263629735e-5L
163 };
164 const long double Q[] = {
165 1.00000000000000000000000000000000000e+0L,
166 -5.20360694854541370154051736496901638e+0L,
167 1.10984640257222420881180161591516337e+1L,
168 -1.24997590867514516374467903875677930e+1L,
169 7.97919868560471967115958363930214958e+0L,
170 -2.87732383715218390800075864637472768e+0L,
171 5.49210416881086355164851972523370137e-1L,
172 -4.73366369162599860878254400521224717e-2L,
173 1.23136575793833628711851523557950417e-3L
174 };
175#else
176 const long double P[] = {
177 1.0706105563309304276767353139512463033e+0L,
178 -1.0976999936495889694316759019749736514e+1L,
179 5.0926847456521671435598196295391041399e+1L,
180 -1.4137651316583179225403308056234710093e+2L,
181 2.6167438966024905838946321639772104746e+2L,
182 -3.4058684964478756354428571563597134889e+2L,
183 3.2038320769322335817541819891481680235e+2L,
184 -2.2042602382067574460998180123431383994e+2L,
185 1.1098617775200190748144566197068215051e+2L,
186 -4.0511655788875306581280201485439376229e+1L,
187 1.0505482055068989911823839054507173824e+1L,
188 -1.8711701614474515075977773430379529915e+0L,
189 2.1700009060344649725726270289240541652e-1L,
190 -1.5030137964245010798524220531488795883e-2L,
191 5.3441650657913964794668981233490297624e-4L,
192 -7.0813883289232115572593407126124042503e-6L,
193 9.9037749983459843207756017329825486520e-9L
194 };
195 const long double Q[] = {
196 1.0000000000000000000000000000000000000e+0L,
197 -1.0552362671556327276432317611336360654e+1L,
198 5.0559576537049301822461383847757604795e+1L,
199 -1.4554341156550484644439941130107249144e+2L,
200 2.8070530313005385434963768448877956414e+2L,
201 -3.8295927403204227055447294669165437162e+2L,
202 3.8034123327297619837621395664129395552e+2L,
203 -2.7878320883603471098333035075019703189e+2L,
204 1.5127204204944666467295435798726892255e+2L,
205 -6.0401294167088266781532200159750431265e+1L,
206 1.7480717870136655299932069333598290551e+1L,
207 -3.5731199220918363429317367913920234597e+0L,
208 4.9537900060585746351429453828993042241e-1L,
209 -4.3750415383481013167382471956794084257e-2L,
210 2.2234568413141078158637017098109483650e-3L,
211 -5.4149527323164210917629185927908003034e-5L,
212 4.1629116823949062782848730828350635143e-7L
213 };
214#endif
215
216 long double y = 0, r = 0, s = 1;
217
218 // transform to [0, 1/2)
219 if (x < -1) {
220 const long double l = std::log(1 - x);
221 y = 1/(1 - x);
222 r = -PI*PI/6 + l*(0.5L*l - std::log(-x));
223 s = 1;
224 } else if (x == -1) {
225 return -PI*PI/12;
226 } else if (x < 0) {
227 const long double l = std::log1p(-x);
228 y = x/(x - 1);
229 r = -0.5L*l*l;
230 s = -1;
231 } else if (x == 0) {
232 return 0;
233 } else if (x < 0.5L) {
234 y = x;
235 r = 0;
236 s = 1;
237 } else if (x < 1) {
238 y = 1 - x;
239 r = PI*PI/6 - std::log(x)*std::log1p(-x);
240 s = -1;
241 } else if (x == 1) {
242 return PI*PI/6;
243 } else if (x < 2) {
244 const long double l = std::log(x);
245 y = 1 - 1/x;
246 r = PI*PI/6 - l*(std::log(y) + 0.5L*l);
247 s = 1;
248 } else {
249 const long double l = std::log(x);
250 y = 1/x;
251 r = PI*PI/3 - 0.5L*l*l;
252 s = -1;
253 }
254
255 const long double z = y - 0.25L;
256
257 const long double p = horner(z, P);
258 const long double q = horner(z, Q);
259
260 return r + s*y*p/q;
261}
262
271std::complex<double> Li2(const std::complex<double>& z_) noexcept
272{
273 const double PI = 3.1415926535897932;
274 const Complex<double> z = { std::real(z_), std::imag(z_) };
275
276 // bf[1..N-1] are the even Bernoulli numbers / (2 n + 1)!
277 // generated by: Table[BernoulliB[2 n]/(2 n + 1)!, {n, 1, 9}]
278 const double bf[10] = {
279 - 1.0/4.0,
280 + 1.0/36.0,
281 - 1.0/3600.0,
282 + 1.0/211680.0,
283 - 1.0/10886400.0,
284 + 1.0/526901760.0,
285 - 4.0647616451442255e-11,
286 + 8.9216910204564526e-13,
287 - 1.9939295860721076e-14,
288 + 4.5189800296199182e-16
289 };
290
291 // special cases
292 if (z.im == 0) {
293 if (z.re <= 1) {
294 return Li2(z.re);
295 }
296 // z.re > 1
297 return { Li2(z.re), -PI*std::log(z.re) };
298 }
299
300 const double nz = norm_sqr(z);
301
303 return z*(1.0 + 0.25*z);
304 }
305
306 Complex<double> u(0.0, 0.0), rest(0.0, 0.0);
307 double sgn = 1;
308
309 // transformation to |z|<1, Re(z)<=0.5
310 if (z.re <= 0.5) {
311 if (nz > 1) {
312 const Complex<double> lz = log(-z);
313 u = -log(1.0 - 1.0 / z);
314 rest = -0.5*lz*lz - PI*PI/6;
315 sgn = -1;
316 } else { // nz <= 1
317 u = -log(1.0 - z);
318 rest = 0;
319 sgn = 1;
320 }
321 } else { // z.re > 0.5
322 if (nz <= 2*z.re) {
323 u = -log(z);
324 rest = u*log(1.0 - z) + PI*PI/6;
325 sgn = -1;
326 } else { // nz > 2*z.re
327 const Complex<double> lz = log(-z);
328 u = -log(1.0 - 1.0 / z);
329 rest = -0.5*lz*lz - PI*PI/6;
330 sgn = -1;
331 }
332 }
333
334 const Complex<double> u2(u*u);
335
336 return sgn*(u + u2*(bf[0] + u*horner<1>(u2, bf))) + rest;
337}
338
347std::complex<long double> Li2(const std::complex<long double>& z_) noexcept
348{
349 const long double PI = 3.14159265358979323846264338327950288L;
350 const Complex<long double> z = { std::real(z_), std::imag(z_) };
351
352 // bf[1..N-1] are the even Bernoulli numbers / (2 n + 1)!
353 // generated by: Table[BernoulliB[2 n]/(2 n + 1)!, {n, 1, 22}]
354 const long double bf[] = {
355 -1.0L/4.0L ,
356 1.0L/36.0L ,
357 -1.0L/3600.0L ,
358 1.0L/211680.0L ,
359 -1.0L/10886400.0L ,
360 1.0L/526901760.0L ,
361 -4.06476164514422552680590938629196667e-11L,
362 8.92169102045645255521798731675274885e-13L,
363 -1.99392958607210756872364434779378971e-14L,
364 4.51898002961991819165047655285559323e-16L,
365 -1.03565176121812470144834115422186567e-17L,
366#if LDBL_DIG > 18
367 2.39521862102618674574028374300098038e-19L,
368 -5.58178587432500933628307450562541991e-21L,
369 1.30915075541832128581230739918659230e-22L,
370 -3.08741980242674029324227976486646243e-24L,
371 7.31597565270220342035790560925214859e-26L,
372 -1.74084565723400074098905514775970255e-27L,
373 4.15763564461389971961789962077522667e-29L,
374 -9.96214848828462210319400670245583885e-31L,
375 2.39403442489616530052116798789374956e-32L,
376 -5.76834735536739008429179316187765424e-34L,
377 1.39317947964700797782788660391154833e-35L,
378 -3.37212196548508947046847363525493096e-37L
379#endif
380 };
381
382 // special cases
383 if (z.im == 0) {
384 if (z.re <= 1) {
385 return Li2(z.re);
386 }
387 // z.re > 1
388 return { Li2(z.re), -PI*std::log(z.re) };
389 }
390
391 const long double nz = norm_sqr(z);
392
394 return z*(1.0L + 0.25L*z);
395 }
396
397 Complex<long double> u(0.0L, 0.0L), rest(0.0L, 0.0L);
398 long double sgn = 1;
399
400 // transformation to |z|<1, Re(z)<=0.5
401 if (z.re <= 0.5L) {
402 if (nz > 1) {
403 const Complex<long double> lz = log(-z);
404 u = -log(1.0L - 1.0L/z);
405 rest = -0.5L*lz*lz - PI*PI/6;
406 sgn = -1;
407 } else { // nz <= 1
408 u = -log(1.0L - z);
409 rest = 0;
410 sgn = 1;
411 }
412 } else { // z.re > 0.5L
413 if (nz <= 2*z.re) {
414 u = -log(z);
415 rest = u*log(1.0L - z) + PI*PI/6;
416 sgn = -1;
417 } else { // nz > 2*z.re
418 const Complex<long double> lz = log(-z);
419 u = -log(1.0L - 1.0L/z);
420 rest = -0.5L*lz*lz - PI*PI/6;
421 sgn = -1;
422 }
423 }
424
425 const Complex<long double> u2(u*u);
426
427 return sgn*(u + u2*(bf[0] + u*horner<1>(u2, bf))) + rest;
428}
429
430} // namespace flexiblesusy
#define P(i)
Definition: defs.h:630
Complex< T > horner(const Complex< T > &z, const T(&coeffs)[N]) noexcept
Definition: Li2.cpp:40
const Real epsilon
Definition: mathdefs.hpp:18
double Li2(double x) noexcept
Real dilogarithm .
Definition: Li2.cpp:68
constexpr T norm_sqr(const Complex< T > &z) noexcept
Definition: complex.hpp:72
Complex< T > log(const Complex< T > &z) noexcept
Definition: complex.hpp:54
Class representing complex a number.
Definition: complex.hpp:34