Skip to main content

rustymath_core/
complex.rs

1//! Complex functions at `Complex<f32>` and `Complex<f64>`: the exponential and logarithm, square root and powers, the circle and hyperbolic functions and their inverses, ln Γ and Γ, binomial coefficients, the magnitude and angle, and the sign z/|z|. Each computes at its own width. The facts table calls their scalar bodies or bulk bodies that run real-array kernels over the parts.
2//!
3//! Their error counts in ulps of the result's magnitude: |f(z) - exact| is within 4 ulps of |exact|. A part much smaller than the other can carry most of that error. ln Γ counts in ulps of the larger of its magnitude and 2. The functions that exponentiate a logarithm count in ulps of their magnitude times one more than the exponent's magnitude, or than 2 where that is smaller: |w ln z| for powers, and |ln Γ| for Γ and binomial coefficients. Branch cuts follow C99's Annex G: the sign of a zero part chooses the side of a cut. The inverse functions use the formulas from Kahan's "Branch Cuts for Complex Elementary Functions" (1987), built on the complex square root, which keep their digits near the branch points.
4//!
5//! `exp` and the powers that compute through it give an exact direction at the float nearest a whole number of quarter turns. e^(iπ/2) is then exactly i, where the exponential of that float has a real part of about 6e-17. These results lie outside the error bound.
6use crate::{Native, arc, exp as e, float::ln2, hyperbolic, ln as l, pow as p, special, trig};
7use num_complex::Complex;
8
9pub(crate) mod bulk;
10
11#[inline(always)]
12fn c<R>(re: R, im: R) -> Complex<R> { Complex::new(re, im) }
13
14/// iz, a quarter turn of z.
15#[inline(always)]
16fn turned<R: Native>(z: Complex<R>) -> Complex<R> { c(-z.im, z.re) }
17
18/// -iz, a quarter turn back.
19#[inline(always)]
20fn unturned<R: Native>(z: Complex<R>) -> Complex<R> { c(z.im, -z.re) }
21
22/// π.
23#[inline(always)]
24fn pi<R: Native>() -> R { let (hi, _) = arc::half_pi::<R>(); hi + hi }
25
26/// The whole number k nearest y/(π/2), and whether y is the float nearest kπ/2, with |k| up to 256.
27#[inline(always)]
28fn turns<R: Native>(y: R) -> (R, bool) {
29    let (q, _) = arc::half_pi::<R>();
30    let k = (y * R::narrow(std::f64::consts::FRAC_2_PI)).round_ties_even();
31    (k, (k.abs() <= R::narrow(256.0)) & (k * q == y))
32}
33
34/// cos y and sin y as exactly 1, 0 or -1, where y is the float nearest kπ/2 for a whole number k of quarter turns, with |k| up to 256. A zero y keeps its sign as sin y.
35#[inline(always)]
36pub(crate) fn quarter<R: Native>(y: R) -> Option<(R, R)> {
37    let (k, exact) = turns(y);
38    if !exact { return None; }
39    let (zero, one, m) = (R::zero(), R::one(), k - R::narrow(4.0) * (k * R::narrow(0.25)).floor());
40    Some(if m == zero { (one, if y == zero { y }
41    else { zero }) }
42    else if m == one { (zero, one) }
43    else if m == one + one { (-one, zero) }
44    else { (zero, -one) })
45}
46
47/// A part of e^z: `scale` times `d`, the cosine or sine of y. A part that `quarter` makes exactly 0 stays 0, even where e^x overflows, unless x is NaN.
48#[inline(always)]
49fn part<R: Native>(x: R, d: R, scale: R) -> R { if (d == R::zero()) & !x.is_nan() { d } else { scale * d } }
50
51/// x / y for complex numbers, inline in the caller's loop, by num_complex's formula. Two real arguments divide as reals, so a real zero divisor gives ±∞ or NaN with an imaginary part of 0. Any other zero divisor gives NaN parts. |y|² overflows beyond about 1e154 at f64 and 1e19 at f32, and underflows below their inverses, where the quotient loses its digits. The decompositions' `Scalar::quotient` uses Smith's algorithm, which avoids that at the cost of speed in a vector loop.
52#[inline(always)]
53pub fn divide<R: Native>(x: Complex<R>, y: Complex<R>) -> Complex<R> {
54    if (x.im == R::zero()) & (y.im == R::zero()) { c(x.re / y.re, R::zero()) } else { x / y }
55}
56
57/// |z| for the scalar functions. At f64 it is `hypot`. At f32 it adds the squares of z's parts in f64, where no square overflows or loses bits, and rounds the root once. That is within half an ulp, where `hypot` at f32's own width is within about one, and it costs less than `hypot`'s scaling.
58#[inline(always)]
59pub(crate) fn modulus<R: Native, const FUSED: bool>(x: R, y: R) -> R {
60    let (a, b) = (x.wide(), y.wide());
61    if R::WIDE { p::hypot::<R, FUSED>(x, y) } else { R::narrow((a * a + b * b).sqrt()) }
62}
63
64/// e^z = e^x (cos y + i sin y). A y that is the float nearest a whole number of quarter turns, up to 256 of them, gives an exact direction: e^(iπ/2) is i and e^(iπ) is -1. e^x/2 times 2 cos y keeps the result finite where e^x overflows but the result doesn't. A real z gives a real result. At x = -∞ the result is 0, and at x = ∞ with an infinite or NaN y it is ∞ + i NaN.
65#[inline]
66pub(crate) fn exp<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> {
67    let (x, y) = (z.re, z.im);
68    let half = e::exp_times::<R, FUSED>(x, -R::one());
69    let (cy, sy) = quarter(y).unwrap_or_else(|| (trig::cos::<R, FUSED>(y), trig::sin::<R, FUSED>(y)));
70    let r = c(part(x, cy + cy, half), if y == R::zero() { y } else { part(x, sy + sy, half) });
71    let lost = x.is_infinite() & !y.is_finite();
72    if lost { if x > R::zero() { c(x, R::nan()) } else { c(R::zero(), R::zero().copysign(y)) } } else { r }
73}
74
75/// z scaled up exactly by 2^(2p) where it is so small that its halves or its magnitude would lose bits, and p, or z itself and 0. p is the number of bits in `R`'s significand.
76#[inline(always)]
77fn scaled<R: Native>(z: Complex<R>) -> (Complex<R>, R) {
78    let (low, scale, p) = if R::WIDE { (1.0020841800044864e-292, 8.112963841460668e31, 53.0) } else { (9.860761315262648e-32, 2.81474976710656e14, 24.0) };
79    if z.re.abs().max(z.im.abs()) < R::narrow(low) { (z * R::narrow(scale), R::narrow(p)) } else { (z, R::zero()) }
80}
81
82/// ln z = ln |z| + i arg z. Where |z| is near 1, ln |z| is ½ log1p((x-1)(x+1) + y²), which keeps its digits. A tiny z scales up first, so that |z| stays normal.
83#[inline]
84pub(crate) fn ln<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> {
85    let (x, y) = (z.re, z.im);
86    let (w, p) = scaled(z);
87    let (hi, lo) = ln2::<R>();
88    let h = modulus::<R, FUSED>(w.re, w.im);
89    let near = (h > R::narrow(0.5)) & (h < R::narrow(2.0));
90    let t = (x - R::one()).mla::<FUSED>(x + R::one(), y * y);
91    let k = p + p;
92    c(if near { l::log1p::<R, FUSED>(t) * R::narrow(0.5) } else { l::ln::<R, FUSED>(h) - k * hi - k * lo }, arc::atan2::<R, FUSED>(y, x))
93}
94
95/// ln(1 + w). Below |w| = ½, ln |1 + w| is ½ log1p(u(2+u) + v²), preserving digits near zero.
96#[inline]
97pub(crate) fn ln1p<R: Native, const FUSED: bool>(w: Complex<R>) -> Complex<R> {
98    let (u, v) = (w.re, w.im);
99    let small = modulus::<R, FUSED>(u, v) < R::narrow(0.5);
100    let t = u.mla::<FUSED>(u + R::narrow(2.0), v * v);
101    let re = if small { l::log1p::<R, FUSED>(t) * R::narrow(0.5) } else { l::ln::<R, FUSED>(modulus::<R, FUSED>(R::one() + u, v)) };
102    c(re, arc::atan2::<R, FUSED>(v, R::one() + u))
103}
104
105/// The parts of √(x + iy), whose real part is never negative, from x, y and h = |x + iy|. t = √((|x| + h)/2) is one part, and y/2t the other, which doesn't cancel. |y|/2t is |y/2t| exactly, so one division serves both signs of x.
106#[inline(always)]
107fn root<R: Native, const FUSED: bool>(x: R, y: R, h: R) -> (R, R) {
108    let t = x.abs().mla::<FUSED>(R::narrow(0.5), h * R::narrow(0.5)).sqrt();
109    let q = y / (t + t);
110    if x >= R::zero() { (t, q) } else { (q.abs(), t.copysign(y)) }
111}
112
113/// √z, through `root` on z and |z|. A tiny z scales up by 2^(2p) first, so that its halves stay normal, and its root back by 2^-p. Zero gives itself, and an infinite y gives ∞ + iy, even beside NaN.
114#[inline]
115pub(crate) fn sqrt<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> {
116    let (x, y) = (z.re, z.im);
117    let (w, p) = scaled(z);
118    let (re, im) = root::<R, FUSED>(w.re, w.im, modulus::<R, FUSED>(w.re, w.im));
119    let k = R::pow2(R::SHIFT - p);
120    if y.is_infinite() { c(R::infinity(), y) } else if (x == R::zero()) & (y == R::zero()) { c(R::zero(), y) } else { c(re * k, im * k) }
121}
122
123/// Whether z^w takes a special case of `pow`: w = 0, z = 0 with Re w > 0, or a real z and w whose power is real, which is a z from 0 up or a whole w.
124#[inline(always)]
125fn pow_cases<R: Native>(z: Complex<R>, w: Complex<R>) -> (bool, bool, bool) {
126    let unit = (w.re == R::zero()) & (w.im == R::zero());
127    let zero = (z.re == R::zero()) & (z.im == R::zero()) & (w.re > R::zero());
128    (unit, zero, (z.im == R::zero()) & (w.im == R::zero()) & ((z.re >= R::zero()) | (w.re == w.re.trunc())))
129}
130
131/// z^w = e^(w ln z). w = 0 gives 1, even for NaN, and z = 0 gives 0 where Re w > 0. A real z and w whose power is real give the real power, as `pow` gives it. Its error grows with |w ln z|, as the module doc gives it.
132#[inline]
133pub(crate) fn pow<R: Native, const FUSED: bool>(z: Complex<R>, w: Complex<R>) -> Complex<R> {
134    let (unit, zero, real) = pow_cases(z, w);
135    let r = p::pow::<R, FUSED>(z.re, w.re);
136    let general = exp::<R, FUSED>(w * ln::<R, FUSED>(z));
137    if unit { c(R::one(), R::zero()) } else if zero { c(R::zero(), R::zero()) } else if real { c(r, R::zero()) } else { general }
138}
139
140pub(crate) fn nth_root<R: Native, const FUSED: bool>(n: Complex<R>, y: Complex<R>) -> Complex<R> {
141    if n == c(R::zero(), R::zero()) || !finite(n) { return c(R::nan(), R::nan()); }
142    if n == c(R::narrow(2.0), R::zero()) { sqrt::<R, FUSED>(y) } else { pow::<R, FUSED>(y, divide(c(R::one(), R::zero()), n)) }
143}
144
145/// sinh z = sinh x cos y + i cosh x sin y. A real z gives a real result and an imaginary z an imaginary one, even where cosh x overflows or cos y is NaN.
146#[inline]
147pub(crate) fn sinh<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> {
148    let (x, y) = (z.re, z.im);
149    let re = hyperbolic::sinh::<R, FUSED>(x) * trig::cos::<R, FUSED>(y);
150    let im = hyperbolic::cosh::<R, FUSED>(x) * trig::sin::<R, FUSED>(y);
151    c(if x == R::zero() { x } else { re }, if y == R::zero() { y } else { im })
152}
153
154/// cosh z = cosh x cos y + i sinh x sin y. A real or imaginary z gives an imaginary part of ±0.
155#[inline]
156pub(crate) fn cosh<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> {
157    let (x, y) = (z.re, z.im);
158    let re = hyperbolic::cosh::<R, FUSED>(x) * trig::cos::<R, FUSED>(y);
159    let im = hyperbolic::sinh::<R, FUSED>(x) * trig::sin::<R, FUSED>(y);
160    c(re, if (x == R::zero()) | (y == R::zero()) { R::zero().copysign(x) * R::zero().copysign(y) } else { im })
161}
162
163/// tanh z by Kahan's formula: with t = tan y, s = sinh x and ρ = √(1 + s²) = cosh x, tanh z = ((1+t²)ρs + it)/(1 + (1+t²)s²). Beyond a magnitude where tanh x rounds to ±1, the result is ±1 + 4 sin y cos y e^(-2|x|) i, which can't overflow.
164#[inline]
165pub(crate) fn tanh<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> {
166    let (x, y) = (z.re, z.im);
167    let (sy, cy) = (trig::sin::<R, FUSED>(y), trig::cos::<R, FUSED>(y));
168    let t = sy / cy;
169    let b = t.mla::<FUSED>(t, R::one());
170    let s = hyperbolic::sinh::<R, FUSED>(x);
171    let rho = s.mla::<FUSED>(s, R::one()).sqrt();
172    let d = (b * s).mla::<FUSED>(s, R::one());
173    let near = c(b * s * rho / d, t / d);
174    let far = c(R::one().copysign(x), e::exp_times::<R, FUSED>(R::narrow(-2.0) * x.abs(), R::narrow(2.0)) * (sy * cy));
175    let r = if x.abs() > tanh_limit::<R>() { far } else { near };
176    if x.is_infinite() & !y.is_finite() { c(r.re, R::zero().copysign(y)) } else { r }
177}
178
179/// The `|x|` beyond which `tanh` takes its formula for a large `x`.
180fn tanh_limit<R: Native>() -> R { R::narrow(if R::WIDE { 22.0 } else { 10.0 }) }
181
182/// sin z = -i sinh(iz).
183#[inline]
184pub(crate) fn sin<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> { unturned(sinh::<R, FUSED>(turned(z))) }
185
186/// cos z = cosh(iz).
187#[inline]
188pub(crate) fn cos<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> { cosh::<R, FUSED>(turned(z)) }
189
190/// tan z = -i tanh(iz).
191#[inline]
192pub(crate) fn tan<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> { unturned(tanh::<R, FUSED>(turned(z))) }
193
194/// √(1 - z) and √(1 + z), whose products give the inverse circle functions.
195#[inline(always)]
196fn roots<R: Native, const FUSED: bool>(z: Complex<R>) -> (Complex<R>, Complex<R>) {
197    (sqrt::<R, FUSED>(c(R::one() - z.re, -z.im)), sqrt::<R, FUSED>(c(R::one() + z.re, z.im)))
198}
199
200/// √(z - 1) and √(z + 1), whose products give acosh and √(z² - 1).
201#[inline(always)]
202fn shifted_roots<R: Native, const FUSED: bool>(z: Complex<R>) -> (Complex<R>, Complex<R>) {
203    (sqrt::<R, FUSED>(c(z.re - R::one(), z.im)), sqrt::<R, FUSED>(c(z.re + R::one(), z.im)))
204}
205
206/// `r`, a square root of a number whose imaginary part is 2xy, with its smaller part recomputed as xy divided by its larger part. A product of two square roots, as `sqrt1mx2` and `sqrtx2m1` form, loses the smaller part where x is too small to change 1 ± x. The product xy keeps it. The larger of x and y is divided first, so a huge x with a tiny y doesn't underflow. `r` stays as it is where x or y is 0, to keep the signs of zeros on the branch cuts, and where a part isn't finite. It selects between values in place of branching, so a loop over a slice vectorizes.
207#[inline(always)]
208fn balanced<R: Native>(r: Complex<R>, x: R, y: R) -> Complex<R> {
209    let zero = R::zero();
210    let swap = x.abs() < y.abs();
211    let (hi, lo) = (if swap { y } else { x }, if swap { x } else { y });
212    let wide = r.re.abs() >= r.im.abs();
213    let big = if wide { r.re } else { r.im };
214    let keep = (x == zero) | (y == zero) | (big == zero) | !(r.re.is_finite() & r.im.is_finite() & x.is_finite() & y.is_finite());
215    let small = if keep { if wide { r.im } else { r.re } } else { hi / big * lo };
216    if wide { c(r.re, small) } else { c(small, r.im) }
217}
218
219/// √(1 - z²) as √(1 - z) √(1 + z), whose real part is never negative. Neither factor loses digits near z = ±1, or overflows where z² would. [`balanced`] restores the smaller part where z's real part is too small to change 1.
220#[inline]
221pub(crate) fn sqrt1mx2<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> { let (a, b) = roots::<R, FUSED>(z); balanced(a * b, -z.re, z.im) }
222
223/// √(1 + z²) as `sqrt1mx2` at iz, because 1 + z² is 1 - (iz)². Its real part is never negative. Neither factor overflows where z² would.
224#[inline]
225pub(crate) fn sqrt1px2<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> { sqrt1mx2::<R, FUSED>(turned(z)) }
226
227/// √(z - 1) √(z + 1), the continuation of the real `sqrtx2m1` off the real line. Neither factor loses digits near z = ±1, or overflows where z² would. [`balanced`] restores the smaller part where z's real part is too small to change 1.
228#[inline]
229pub(crate) fn sqrtx2m1<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> { let (a, b) = shifted_roots::<R, FUSED>(z); balanced(a * b, z.re, z.im) }
230
231pub(crate) fn sqrtm1mx2<R: Native, const FUSED: bool>(z: Complex<R>, inverse: bool) -> Complex<R> {
232    let r = if z.im == R::zero() { c(R::zero(), crate::sqrts::sqrt1px2::<R, FUSED>(z.re)) } else { sqrt::<R, FUSED>(-c(R::one(), R::zero()) - z * z) };
233    if inverse { -r } else { r }
234}
235
236/// asin z, by Kahan's formula: with a = √(1 - z) and b = √(1 + z), Re asin z = atan(x / Re(ab)) and Im asin z = asinh(Im(conj(a) b)).
237#[inline]
238pub(crate) fn asin<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> {
239    let (a, b) = roots::<R, FUSED>(z);
240    let re = arc::atan2::<R, FUSED>(z.re, a.re.mla::<FUSED>(b.re, -(a.im * b.im)));
241    c(re, hyperbolic::asinh::<R, FUSED>(a.re.mla::<FUSED>(b.im, -(a.im * b.re))))
242}
243
244/// acos z, by Kahan's formula: with a = √(1 - z) and b = √(1 + z), Re acos z = 2 atan(Re a / Re b) and Im acos z = asinh(Im(conj(b) a)).
245#[inline]
246pub(crate) fn acos<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> {
247    let (a, b) = roots::<R, FUSED>(z);
248    let re = arc::atan2::<R, FUSED>(a.re, b.re);
249    c(re + re, hyperbolic::asinh::<R, FUSED>(b.re.mla::<FUSED>(a.im, -(b.im * a.re))))
250}
251
252/// acosh z, by Kahan's formula: with a = √(z - 1) and b = √(z + 1), Re acosh z = asinh(Re(conj(a) b)) and Im acosh z = 2 atan(Im a / Re b).
253#[inline]
254pub(crate) fn acosh<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> {
255    let (a, b) = shifted_roots::<R, FUSED>(z);
256    let im = arc::atan2::<R, FUSED>(a.im, b.re);
257    c(hyperbolic::asinh::<R, FUSED>(a.re.mla::<FUSED>(b.re, a.im * b.im)), im + im)
258}
259
260/// asinh z = -i asin(iz).
261#[inline]
262pub(crate) fn asinh<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> { unturned(asin::<R, FUSED>(turned(z))) }
263
264/// atanh z, with Re atanh z = ¼ log1p(4x / ((1-x)² + y²)) and Im atanh z = ½ atan2(2y, (1-x)(1+x) - y²). atanh is odd, so it computes at |x|, where the argument of log1p is from 0 up and loses nothing. Where the squares would overflow, Re atanh z is x/|z|² and Im atanh z is ±π/2. An infinite part gives ±0 ± iπ/2.
265#[inline]
266pub(crate) fn atanh<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> {
267    let s = R::one().copysign(z.re);
268    let (x, y) = (z.re.abs(), z.im * s);
269    let (m, quarter, half) = (R::one() - x, R::narrow(0.25), R::narrow(0.5));
270    let re = l::log1p::<R, FUSED>(R::narrow(4.0) * x / m.mla::<FUSED>(m, y * y)) * quarter;
271    let im = arc::atan2::<R, FUSED>(y + y, m.mla::<FUSED>(R::one() + x, -(y * y))) * half;
272    let h = modulus::<R, FUSED>(x, y);
273    let (right, _) = arc::half_pi::<R>();
274    let huge = h > atanh_huge::<R>();
275    let (re, im) = if x.is_infinite() | y.is_infinite() { (R::zero(), right.copysign(y)) } else if huge { (x / h / h, right.copysign(y)) } else { (re, im) };
276    c(re * s, im * s)
277}
278
279/// The modulus beyond which `atanh` takes its formula for a huge `z`.
280fn atanh_huge<R: Native>() -> R { R::narrow(if R::WIDE { 1e150 } else { 1e18 }) }
281
282/// atan z = -i atanh(iz).
283#[inline]
284pub(crate) fn atan<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> { unturned(atanh::<R, FUSED>(turned(z))) }
285
286/// Whether z is a pole of Γ: a whole number from 0 down.
287#[inline(always)]
288fn pole<R: Native>(z: Complex<R>) -> bool { (z.im == R::zero()) & (z.re <= R::zero()) & (z.re == z.re.trunc()) }
289
290/// ln Γ(w) by Stirling's series, for |w| from 7 up, away from the negative real axis: (w - ½) ln w - w + ½ ln 2π + (1/w) S(1/w²), with the ten terms of `special::STIRLING`.
291#[inline]
292fn stirling<R: Native, const FUSED: bool>(w: Complex<R>) -> Complex<R> {
293    let n = w.re.mla::<FUSED>(w.re, w.im * w.im);
294    let v = c(w.re / n, -w.im / n);
295    let v2 = v * v;
296    let mut s = c(R::narrow(special::STIRLING[0]), R::zero());
297    for &k in &special::STIRLING[1..] { s = s * v2 + c(R::narrow(k), R::zero()); }
298    c(w.re - R::narrow(0.5), w.im) * ln::<R, FUSED>(w) - w + c(R::narrow(special::HALF_LN_2PI), R::zero()) + v * s
299}
300
301/// ln Γ(w) for Re w from 0.1 up: `stirling` itself where Re w or |Im w| is 7 or more, and otherwise ln Γ(w + n) - ln(w(w+1)…(w+n-1)) with n the steps that bring Re w to 7. Above the real axis, the product's argument grows with each factor. Each time it passes π the product's imaginary part turns negative, and the principal logarithm drops 2π, which the result adds back. Below the axis it is the conjugate of the result above.
302#[inline]
303fn shifted<R: Native, const FUSED: bool>(w: Complex<R>) -> Complex<R> {
304    let below = w.im.is_sign_negative();
305    let mut z = if below { w.conj() } else { w };
306    let seven = R::narrow(7.0);
307    let r = if (z.re >= seven) | (z.im >= seven) { stirling::<R, FUSED>(z) } else {
308        let (mut product, mut turns, mut negative) = (z, R::zero(), false);
309        z.re = z.re + R::one();
310        while z.re < seven {
311            product = product * z;
312            let now = product.im.is_sign_negative();
313            if now & !negative { turns = turns + R::one(); }
314            negative = now;
315            z.re = z.re + R::one();
316        }
317        stirling::<R, FUSED>(z) - ln::<R, FUSED>(product) - c(R::zero(), (pi::<R>() + pi::<R>()) * turns)
318    };
319    if below { r.conj() } else { r }
320}
321
322/// ln π - ln sin πu, for Im u from 0 up. sin πu = (i/2) e^(-iπu) (1 - e^(2πiu)), so this is ln 2π - πy + iπ(x - ½) - ln(1 - e^(2πiu)), which stays finite where sin πu overflows. The imaginary part isn't reduced, which keeps it continuous over the half-plane.
323#[inline]
324fn reflected<R: Native, const FUSED: bool>(u: Complex<R>) -> Complex<R> {
325    let (x, y) = (u.re, u.im);
326    let (s, k) = crate::recipe::sincospi(&crate::recipe::Floats, x + x);
327    let m = e::exp::<R, FUSED>(R::narrow(-2.0) * pi::<R>() * y);
328    let t = ln1p::<R, FUSED>(c(-(m * k), -(m * s)));
329    c((R::narrow(1.8378770664093453) - pi::<R>() * y) - t.re, pi::<R>() * (x - R::narrow(0.5)) - t.im)
330}
331
332/// ln Γ(z), on the branch that is real on the positive real axis and continuous everywhere but across the negative real axis, as SciPy's and mpmath's `loggamma` give it. Below Re z = 0.1 it reflects: ln Γ(z) = ln π - ln sin πz - ln Γ(1 - z), and the lower half-plane gives the conjugate of the upper. Elsewhere it is `shifted`. Poles and non-finite arguments give NaN. Near the zeros at 1 and 2 the error counts in ulps of 2, not of the result.
333#[inline]
334pub(crate) fn lgamma<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> {
335    if !(z.re.is_finite() & z.im.is_finite()) | pole(z) { return c(R::nan(), R::nan()); }
336    if z.re >= R::narrow(0.1) { return shifted::<R, FUSED>(z); }
337    let below = z.im.is_sign_negative();
338    let u = if below { z.conj() } else { z };
339    let r = reflected::<R, FUSED>(u) - shifted::<R, FUSED>(c(R::one() - u.re, -u.im));
340    if below { r.conj() } else { r }
341}
342
343/// Γ(z) = e^(ln Γ(z)). Its error grows with |ln Γ(z)|, as the module doc gives it. The poles give NaN.
344#[inline]
345pub(crate) fn gamma<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> { exp::<R, FUSED>(lgamma::<R, FUSED>(z)) }
346/// Γ(z + 1).
347#[inline]
348pub(crate) fn factorial<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> { gamma::<R, FUSED>(c(z.re + R::one(), z.im)) }
349
350/// The binomial coefficient Γ(n+1) / (Γ(k+1) Γ(n-k+1)), as e^(ln Γ(n+1) - ln Γ(k+1) - ln Γ(n-k+1)). A pole in the denominator gives 0, and one in the numerator NaN.
351#[inline]
352pub(crate) fn binom<R: Native, const FUSED: bool>(n: Complex<R>, k: Complex<R>) -> Complex<R> {
353    let one = c(R::one(), R::zero());
354    let (a, b, d) = (n + one, k + one, n - k + one);
355    let r = exp::<R, FUSED>(lgamma::<R, FUSED>(a) - lgamma::<R, FUSED>(b) - lgamma::<R, FUSED>(d));
356    if !pole(a) & (pole(b) | pole(d)) { c(R::zero(), R::zero()) } else { r }
357}
358
359/// z/|z|, of magnitude 1 in the direction of z. Zero gives itself, and an infinity the direction of its infinite parts.
360#[inline]
361pub(crate) fn sign<R: Native, const FUSED: bool>(z: Complex<R>) -> Complex<R> {
362    let unit = |v: R| (if v.is_infinite() { R::one() } else { R::zero() }).copysign(v);
363    let w = if z.re.is_infinite() | z.im.is_infinite() { c(unit(z.re), unit(z.im)) } else { z };
364    let h = modulus::<R, FUSED>(w.re, w.im);
365    if h == R::zero() { z } else { c(w.re / h, w.im / h) }
366}
367
368/// Whether both parts of z are finite.
369#[inline(always)]
370fn finite<R: Native>(z: Complex<R>) -> bool { z.re.is_finite() & z.im.is_finite() }
371
372/// e^(iz), the cis of z, as a function object, which is cos z + i sin z for a real z. It takes real and complex items.
373#[derive(Clone, Copy, Debug)]
374pub struct Cis;