flexiblesusy is hosted by Hepforge, IPPP Durham
FlexibleSUSY
Li3.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 "Li3.hpp"
20#include "complex.hpp"
21#include <cfloat>
22#include <cmath>
23
24namespace flexiblesusy {
25
26namespace {
27
28 template <typename T, int N>
29 Complex<T> horner(const Complex<T>& z, const T (&coeffs)[N]) noexcept
30 {
31 static_assert(N >= 2, "more than two coefficients required");
32
33 const T r = z.re + z.re;
34 const T s = z.re * z.re + z.im * z.im;
35 T a = coeffs[N - 1], b = coeffs[N - 2];
36
37 for (int i = N - 3; i >= 0; --i) {
38 const T t = a;
39 a = b + r * a;
40 b = coeffs[i] - s * t;
41 }
42
43 return Complex<T>(z.re*a + b, z.im*a);
44 }
45
47 double li3_neg(double x) noexcept
48 {
49 const double cp[] = {
50 0.9999999999999999795e+0, -2.0281801754117129576e+0,
51 1.4364029887561718540e+0, -4.2240680435713030268e-1,
52 4.7296746450884096877e-2, -1.3453536579918419568e-3
53 };
54 const double cq[] = {
55 1.0000000000000000000e+0, -2.1531801754117049035e+0,
56 1.6685134736461140517e+0, -5.6684857464584544310e-1,
57 8.1999463370623961084e-2, -4.0756048502924149389e-3,
58 3.4316398489103212699e-5
59 };
60
61 const double x2 = x*x;
62 const double x4 = x2*x2;
63 const double p = cp[0] + x*cp[1] + x2*(cp[2] + x*cp[3]) +
64 x4*(cp[4] + x*cp[5]);
65 const double q = cq[0] + x*cq[1] + x2*(cq[2] + x*cq[3]) +
66 x4*(cq[4] + x*cq[5] + x2*cq[6]);
67
68 return x*p/q;
69 }
70
72 double li3_pos(double x) noexcept
73 {
74 const double cp[] = {
75 0.9999999999999999893e+0, -2.5224717303769789628e+0,
76 2.3204919140887894133e+0, -9.3980973288965037869e-1,
77 1.5728950200990509052e-1, -7.5485193983677071129e-3
78 };
79 const double cq[] = {
80 1.0000000000000000000e+0, -2.6474717303769836244e+0,
81 2.6143888433492184741e+0, -1.1841788297857667038e+0,
82 2.4184938524793651120e-1, -1.8220900115898156346e-2,
83 2.4927971540017376759e-4
84 };
85
86 const double x2 = x*x;
87 const double x4 = x2*x2;
88 const double p = cp[0] + x*cp[1] + x2*(cp[2] + x*cp[3]) +
89 x4*(cp[4] + x*cp[5]);
90 const double q = cq[0] + x*cq[1] + x2*(cq[2] + x*cq[3]) +
91 x4*(cq[4] + x*cq[5] + x2*cq[6]);
92
93 return x*p/q;
94 }
95
96} // anonymous namespace
97
104double Li3(double x) noexcept
105{
106 const double zeta2 = 1.6449340668482264;
107 const double zeta3 = 1.2020569031595943;
108
109 // transformation to [-1,0] and [0,1/2]
110 if (x < -1) {
111 const double l = std::log(-x);
112 return li3_neg(1/x) - l*(zeta2 + 1.0/6*l*l);
113 } else if (x == -1) {
114 return -0.75*zeta3;
115 } else if (x < 0) {
116 return li3_neg(x);
117 } else if (x == 0) {
118 return 0;
119 } else if (x < 0.5) {
120 return li3_pos(x);
121 } else if (x == 0.5) {
122 return 0.53721319360804020;
123 } else if (x < 1) {
124 const double l = std::log(x);
125 return -li3_neg(1 - 1/x) - li3_pos(1 - x)
126 + zeta3 + l*(zeta2 + l*(-0.5*std::log1p(-x) + 1.0/6*l));
127 } else if (x == 1) {
128 return zeta3;
129 } else if (x < 2) {
130 const double l = std::log(x);
131 return -li3_neg(1 - x) - li3_pos(1 - 1/x)
132 + zeta3 + l*(zeta2 + l*(-0.5*std::log(x - 1) + 1.0/6*l));
133 } else { // x >= 2.0
134 const double l = std::log(x);
135 return li3_pos(1/x) + l*(2*zeta2 - 1.0/6*l*l);
136 }
137}
138
145std::complex<double> Li3(const std::complex<double>& z_) noexcept
146{
147 const double PI = 3.1415926535897932;
148 const double zeta2 = 1.6449340668482264;
149 const double zeta3 = 1.2020569031595943;
150 const double bf[18] = {
151 1.0 , -3.0/8.0 ,
152 17.0/216.0 , -5.0/576.0 ,
153 1.2962962962962963e-04, 8.1018518518518519e-05,
154 -3.4193571608537595e-06, -1.3286564625850340e-06,
155 8.6608717561098513e-08, 2.5260875955320400e-08,
156 -2.1446944683640648e-09, -5.1401106220129789e-10,
157 5.2495821146008294e-11, 1.0887754406636318e-11,
158 -1.2779396094493695e-12, -2.3698241773087452e-13,
159 3.1043578879654623e-14, 5.2617586299125061e-15
160 };
161
162 const Complex<double> z = { std::real(z_), std::imag(z_) };
163
164 if (z.im == 0) {
165 if (z.re <= 1) {
166 return Li3(z.re);
167 } else {
168 const double l = std::log(z.re);
169 return std::complex<double>(Li3(z.re), -0.5*PI*l*l);
170 }
171 }
172
173 const double nz = norm(z);
174 const double pz = arg(z);
175 const double lnz = std::log(nz);
176
177 if (lnz*lnz + pz*pz < 1) { // |log(z)| < 1
178 const Complex<double> u(lnz, pz); // log(z)
179 const Complex<double> u2 = u*u;
180 const Complex<double> u4 = u2*u2;
181 const Complex<double> u8 = u4*u4;
182 const Complex<double> c0 = zeta3 + u*(zeta2 - u2/12.0);
183 const Complex<double> c1 = 0.25 * (3.0 - 2.0*log(-u));
184
185 const double cs[7] = {
186 -3.4722222222222222e-03, 1.1574074074074074e-05,
187 -9.8418997228521038e-08, 1.1482216343327454e-09,
188 -1.5815724990809166e-11, 2.4195009792525152e-13,
189 -3.9828977769894877e-15
190 };
191
192 return
193 c0 +
194 c1*u2 +
195 u4*(cs[0] + u2*cs[1]) +
196 u8*(cs[2] + u2*cs[3] + u4*(cs[4] + u2*cs[5])) +
197 u8*u8*cs[6];
198 }
199
200 Complex<double> u(0.0, 0.0), rest(0.0, 0.0);
201
202 if (nz <= 1) {
203 u = -log(1.0 - z);
204 } else { // nz > 1
205 const double arg = pz > 0.0 ? pz - PI : pz + PI;
206 const Complex<double> lmz(lnz, arg); // log(-z)
207 u = -log(1.0 - 1.0/z);
208 rest = -lmz*(lmz*lmz/6.0 + zeta2);
209 }
210
211 const Complex<double> u2 = u*u;
212 const Complex<double> u4 = u2*u2;
213 const Complex<double> u8 = u4*u4;
214
215 return
216 rest +
217 u*bf[0] +
218 u2*(bf[1] + u*bf[2]) +
219 u4*(bf[3] + u*bf[4] + u2*(bf[5] + u*bf[6])) +
220 u8*(bf[7] + u*bf[8] + u2*(bf[9] + u*bf[10]) +
221 u4*(bf[11] + u*bf[12] + u2*(bf[13] + u*bf[14]))) +
222 u8*u8*(bf[15] + u*bf[16] + u2*bf[17]);
223}
224
231std::complex<long double> Li3(const std::complex<long double>& z_) noexcept
232{
233 const long double PI = 3.14159265358979323846264338327950288L;
234 const long double zeta2 = 1.64493406684822643647241516664602519L;
235 const long double zeta3 = 1.20205690315959428539973816151144999L;
236 const long double bf[] = {
237 1.0L,
238 -3.0L/8.0L,
239 17.0L/216.0L,
240 -5.0L/576.0L,
241 7.0L/54000.0L,
242 7.0L/86400.0L,
243 -3.41935716085375949321527552820069827e-06L,
244 -1.32865646258503401360544217687074830e-06L,
245 8.66087175610985134794658604182413706e-08L,
246 2.52608759553203997648442092886537331e-08L,
247 -2.14469446836406476093388507573649032e-09L,
248 -5.14011062201297891533581769272004962e-10L,
249 5.24958211460082943639408880855807284e-11L,
250 1.08877544066363183753729715704249107e-11L,
251 -1.27793960944936953055818317540722120e-12L,
252 -2.36982417730874520997977788101244891e-13L,
253 3.10435788796546229428475327046556211e-14L,
254 5.26175862991250608413183925112250061e-15L,
255 -7.53847954994926536599250143226771028e-16L,
256 -1.18623225777522852530825009512459322e-16L,
257 1.83169799654913833820892731212815349e-17L,
258 2.70681710318373501514907347126169436e-18L,
259#if LDBL_DIG > 18
260 -4.45543389782963882643263099217632212e-19L,
261 -6.23754849225569465036532224739838641e-20L,
262 1.08515215348745349131365609968642833e-20L,
263 1.44911748660360819307349049665275324e-21L,
264 -2.64663397544589903347408911861443741e-22L,
265 -3.38976534885101047219258165860814078e-23L,
266 6.46404773360331088903253098219534234e-24L,
267 7.97583448960241242420922272590502795e-25L,
268 -1.58091787902874833559211176293826770e-25L,
269 -1.88614997296228681931102253988531956e-26L,
270 3.87155366384184733039971271888313319e-27L,
271 4.48011750023456073048653898320511684e-28L,
272 -9.49303387191183612641753676027699150e-29L,
273 -1.06828138090773812240182143033807908e-29L,
274 2.33044789361030518600785199019281371e-30L,
275 2.55607757265197540805635698286695865e-31L,
276 -5.72742160613725968447274458033057100e-32L,
277 -6.13471321379642358258549296897773326e-33L,
278 1.40908086040689448401268688489421700e-33L,
279 1.47642223976665341443182801167106626e-34L,
280 -3.47010516489959160555004020312910903e-35L,
281 -3.56210662409746357967357370318293608e-36L,
282 8.55369656823692105754731289124468101e-37L
283#endif
284 };
285
286 const Complex<long double> z = { std::real(z_), std::imag(z_) };
287
288 if (z.im == 0) {
289 if (z.re == 0) {
290 return 0.0L;
291 }
292 if (z.re == 1) {
293 return zeta3;
294 }
295 if (z.re == -1) {
296 return -0.75L*zeta3;
297 }
298 if (z.re == 0.5L) {
299 return 0.537213193608040200940623225594965827L;
300 }
301 }
302
303 const long double nz = norm(z);
304 const long double pz = arg(z);
305 const long double lnz = std::log(nz);
306
307 if (lnz*lnz + pz*pz < 1) { // |log(z)| < 1
308 const Complex<long double> u(lnz, pz); // log(z)
309 const Complex<long double> u2 = u*u;
310 const Complex<long double> c0 = zeta3 + u*(zeta2 - u2/12.0L);
311 const Complex<long double> c1 = 0.25L * (3.0L - 2.0L*log(-u));
312
313 const long double cs[] = {
314 -3.47222222222222222222222222222222222e-03L,
315 1.15740740740740740740740740740740741e-05L,
316 -9.84189972285210380448475686570924666e-08L,
317 1.14822163433274544385655496766607878e-09L,
318 -1.58157249908091658933409775160616911e-11L,
319 2.41950097925251519452732701564998016e-13L,
320 -3.98289777698948774786517290926462002e-15L,
321 6.92336661830592905806820954095065870e-17L,
322 -1.25527223044997727545846570912655367e-18L,
323#if LDBL_DIG > 18
324 2.35375400276846523056441171414060379e-20L,
325 -4.53639890345868701844750708901700830e-22L,
326 8.94516967039264316712031170773304472e-24L,
327 -1.79828400469549627172020247141015426e-25L,
328 3.67549976479373844433604733912674099e-27L,
329 -7.62080797156479522953948500963765478e-29L,
330 1.60004196436948597517376392257325602e-30L,
331 -3.39676114756037558792312060520851852e-32L,
332 7.28227228675776469531725636144432664e-34L,
333 -1.57502264795800348718497893940378261e-35L,
334 3.43354009248058933588797212016527038e-37L
335#endif
336 };
337
338 return c0 + u2*(c1 + u2*horner(u2, cs));
339 }
340
341 Complex<long double> u(0.0L, 0.0L), rest(0.0L, 0.0L);
342
343 if (nz <= 1) {
344 u = -log(1.0L - z);
345 } else { // nz > 1
346 const long double arg = pz > 0.0 ? pz - PI : pz + PI;
347 const Complex<long double> lmz(lnz, arg); // log(-z)
348 u = -log(1.0L - 1.0L/z);
349 rest = -lmz*(lmz*lmz/6.0L + zeta2);
350 }
351
352 return rest + u*horner(u, bf);
353}
354
355} // namespace flexiblesusy
double li3_neg(double x) noexcept
Li_3(x) for x in [-1,0].
Definition: Li3.cpp:47
Complex< T > horner(const Complex< T > &z, const T(&coeffs)[N]) noexcept
Definition: Li3.cpp:29
double li3_pos(double x) noexcept
Li_3(x) for x in [0,1/2].
Definition: Li3.cpp:72
constexpr T norm(const Complex< T > &z) noexcept
Definition: complex.hpp:66
static constexpr double zeta2
Definition: wrappers.hpp:53
constexpr T arg(const Complex< T > &z) noexcept
Definition: complex.hpp:42
double Li3(double x) noexcept
Real trilogarithm .
Definition: Li3.cpp:104
Complex< T > log(const Complex< T > &z) noexcept
Definition: complex.hpp:54
static constexpr double zeta3
Definition: wrappers.hpp:54
double c0(double m1, double m2, double m3) noexcept
Definition: numerics.cpp:373
Class representing complex a number.
Definition: complex.hpp:34