#![allow(clippy::excessive_precision, clippy::approx_constant)]
pub(crate) fn psi(xx: f64) -> f64 {
const XMAX1: f64 = 4.5e15;
const XSMALL: f64 = 5.8e-9;
const XLARGE: f64 = 2.71e14;
const X01: f64 = 187.0;
const X01D: f64 = 128.0;
const X02: f64 = 6.9464496836234126266e-4;
const P1: [f64; 9] = [
0.004510468124576293416,
5.4932855833000385356,
376.46693175929276856,
7952.5490849151998065,
71451.59581895193321,
306559.76301987365674,
636069.97788964458797,
580413.12783537569993,
165856.95029761022321,
];
const Q1: [f64; 8] = [
96.141654774222358525,
2628.771579058119333,
29862.49702225027792,
162065.66091533671639,
434878.80712768329037,
542563.84537269993733,
242421.85002017985252,
6.4155223783576225996e-8,
];
const P2: [f64; 7] = [
-2.7103228277757834192,
-15.166271776896121383,
-19.784554148719218667,
-8.8100958828312219821,
-1.4479614616899842986,
-0.073689600332394549911,
-6.5135387732718171306e-21,
];
const Q2: [f64; 6] = [
44.992760373789365846,
202.40955312679931159,
247.36979003315290057,
107.42543875702278326,
17.463965060678569906,
0.88427520398873480342,
];
const PIOV4: f64 = 0.78539816339744830962;
const XINF: f64 = 1.79e308;
const XMIN1: f64 = 2.23e-308;
let mut x = xx;
let mut w = x.abs();
let mut aug: f64 = 0.0;
if -x >= XMAX1 || w < XMIN1 {
return if x > 0.0 { -XINF } else { XINF };
}
if x >= 0.5 {
} else {
if w <= XSMALL {
aug = -1.0 / x;
} else {
let mut sgn = if x < 0.0 { PIOV4 } else { -PIOV4 };
w -= w.trunc();
let nq = (w * 4.0) as i64;
w = 4.0 * (w - nq as f64 * 0.25);
let mut n = nq / 2;
if n + n != nq {
w = 1.0 - w;
}
let z = PIOV4 * w;
if n % 2 != 0 {
sgn = -sgn;
}
n = (nq + 1) / 2;
if n % 2 == 0 {
if z == 0.0 {
return if x > 0.0 { -XINF } else { XINF };
}
aug = sgn * (4.0 / z.tan());
} else {
aug = sgn * (4.0 * z.tan());
}
}
x = 1.0 - x;
}
if x > 3.0 {
if x < XLARGE {
w = 1.0 / (x * x);
let mut den = w;
let mut upper = P2[0] * w;
for i in 1..=5 {
den = (den + Q2[i - 1]) * w;
upper = (upper + P2[i]) * w;
}
aug += (upper + P2[6]) / (den + Q2[5]) - 0.5 / x;
}
aug + x.ln()
} else {
let mut den = x;
let mut upper = P1[0] * x;
for i in 1..=7 {
den = (den + Q1[i - 1]) * x;
upper = (upper + P1[i]) * x;
}
den = (upper + P1[8]) / (den + Q1[7]);
x -= X01 / X01D + X02;
den * x + aug
}
}
const A: [f64; 12] = [
12.0,
-720.0,
30240.0,
-1209600.0,
47900160.0,
-1.8924375803183791606e9,
7.47242496e10,
-2.950130727918164224e12,
1.1646782814350067249e14,
-4.5979787224074726105e15,
1.8152105401943546773e17,
-7.1661652561756670113e18,
];
const MACHEP: f64 = 1.11022302462515654042e-16;
pub(crate) fn zeta(x: f64, q: f64) -> f64 {
if x == 1.0 {
return f64::INFINITY;
}
if x < 1.0 {
return f64::NAN;
}
if q <= 0.0 {
if q == q.floor() {
return f64::INFINITY;
}
if x != x.floor() {
return f64::NAN; }
}
let mut s = q.powf(-x);
let mut a = q;
let mut b = 0.0;
let mut i = 0u32;
while i < 9 || a <= 9.0 {
a += 1.0;
b = a.powf(-x);
s += b;
if (b / s).abs() < MACHEP {
return s;
}
i += 1;
}
let w = a;
s += b * w / (x - 1.0);
s -= 0.5 * b;
let mut a2 = 1.0;
let mut k = 0.0;
for coeff in A.iter() {
a2 *= x + k;
b /= w;
let t = a2 * b / coeff;
s += t;
if (t / s).abs() < MACHEP {
return s;
}
k += 1.0;
a2 *= x + k;
b /= w;
k += 1.0;
}
s
}