|
| double | elliptic_K (double m) |
| | Complete elliptic integral of the first kind, K(m), m = k^2 in [0, 1).
|
| double | elliptic_E (double m) |
| | Complete elliptic integral of the second kind, E(m), m = k^2 in [0, 1].
|
| double | jacobi_nome (double m) |
| | Jacobi nome q(m) = exp(-pi * K(1 - m) / K(m)).
|
| void | jacobi_sncndn (double u, double m, double *sn_out, double *cn_out, double *dn_out) |
| | Jacobi elliptic functions sn(u, m), cn(u, m), dn(u, m) — all three at once because the AGM-based scheme produces them together.
|
| double | jacobi_sn (double u, double m) |
| | Convenience: sn(u, m).
|
| double | jacobi_cn (double u, double m) |
| | Convenience: cn(u, m).
|
| double | jacobi_dn (double u, double m) |
| | Convenience: dn(u, m).
|
| double | carlson_RF (double x, double y, double z) |
| | Carlson's symmetric elliptic integral of the first kind, RF(x, y, z).
|
| double | jacobi_asn (double x, double m) |
| | Inverse Jacobi sn: returns u such that sn(u, m) = x, for x in [-1, 1].
|
| double pulp::signal::special::carlson_RF |
( |
double | x, |
|
|
double | y, |
|
|
double | z ) |
|
inline |
Carlson's symmetric elliptic integral of the first kind, RF(x, y, z).
Used internally by jacobi_asn(). Carlson's duplication theorem reduces the integral to a power series around the average of the three arguments, converging to machine precision in ~5 iterations for well-conditioned inputs. Reference: B.C. Carlson, "Numerical
Computation of Real or Complex Elliptic Integrals" (1995), and Numerical Recipes 3rd ed. §6.12 (function rf).
Domain: x, y, z >= 0 with at most one of them zero. Caller is responsible for staying inside this domain; we simply clamp negatives to zero so a stray rounding error in jacobi_asn() doesn't escape as NaN into a coefficient stream.
| double pulp::signal::special::elliptic_E |
( |
double | m | ) |
|
|
inline |
Complete elliptic integral of the second kind, E(m), m = k^2 in [0, 1].
AGM-based: track c_n = (a_n - b_n)/2 alongside the AGM iteration; then E(m) = K(m) * (1 - sum_{n=0}^{inf} 2^{n-1} c_n^2) where c_0 = sqrt(m). The c_n sequence shrinks quadratically so a handful of terms suffices. The sum coefficient pattern is 2^{-1}, 2^0, 2^1, ... so we seed pow2 = 1/2 before doubling each step.
E(0) = pi/2 and E(1) = 1 exactly (returned as edge cases).
| double pulp::signal::special::elliptic_K |
( |
double | m | ) |
|
|
inline |
Complete elliptic integral of the first kind, K(m), m = k^2 in [0, 1).
Computed via the arithmetic-geometric mean (AGM): start with (a0, b0) = (1, sqrt(1 - m)); iterate (a_{n+1}, b_{n+1}) = ((a + b)/2, sqrt(a * b)); K(m) = pi / (2 * AGM). Converges quadratically; 8 to 12 iterations reach machine precision for m up to ~1 - 1e-12.
At m = 1 the integral diverges; the implementation returns +infinity. At m = 0 it returns pi/2 exactly.
| double pulp::signal::special::jacobi_asn |
( |
double | x, |
|
|
double | m ) |
|
inline |
Inverse Jacobi sn: returns u such that sn(u, m) = x, for x in [-1, 1].
Implementation: asn(x, m) = x * RF(1 - x^2, 1 - m * x^2, 1). This is the standard Carlson form (Numerical Recipes §6.12), accurate to machine precision across the full m ∈ [0, 1] range. The sign of x carries through naturally since RF is even in its arguments and we only multiply by x.
For m = 0 this reduces to asin(x); for m = 1 it reduces to atanh(x). Inputs outside [-1, 1] are clamped to keep filter-design code numerically safe rather than throwing or NaN-poisoning the cascade.
| void pulp::signal::special::jacobi_sncndn |
( |
double | u, |
|
|
double | m, |
|
|
double * | sn_out, |
|
|
double * | cn_out, |
|
|
double * | dn_out ) |
|
inline |
Jacobi elliptic functions sn(u, m), cn(u, m), dn(u, m) — all three at once because the AGM-based scheme produces them together.
Algorithm: Numerical Recipes 3rd ed. §6.12 (Press et al.). We run the AGM until the two sequences a_n and emc_n agree, then unwind the recursion using the recurrence dn_{n-1} = (em_n + dn_n * a) / (b + a), a := c / b to recover sn / cn / dn at the original modulus. This converges to machine precision in ~6 iterations across the entire m ∈ (0, 1) range without needing per-step asin() calls.
Outputs are written through pointer arguments so callers can request any subset cheaply (pass nullptr for outputs they don't need).