Repository navigation
Jacobi am Implementation
Reference: K. L. Sala, "Transformations of the Jacobian Amplitude Function and Its Calculation via the Arithmetic-Geometric Mean," SIAM J. Math. Anal. 20(6), 1989, pp. 1514–1528.
bf-jacobi-am computes
$\mathrm{gd}(x + iy) = \mathrm{atan2}(\sinh x, \cos y) + i,\tanh^{-1}(\sin y,\mathrm{sech}, x)$ $\mathrm{gd}(A + w) - \mathrm{gd}(A - w) = 2\tan^{-1}\left(\frac{\sinh w}{\cosh A}\right)$
and states where each one, and the related identities
Throughout,
Sala defines
Off these cuts gd is analytic, with
Let
Derivative. Where
and
Branch cuts. Principal
-
$\tanh(u/2)$ is purely imaginary only for$u = iy$ , where$\tanh(iy/2) = i\tan(y/2)$ . -
$\lvert\tan(y/2)\rvert \ge 1$ exactly when$y \in [\pi/2, 3\pi/2] \bmod 2\pi$ . This range also contains the poles of$\tanh(u/2)$ , at$y = \pi \bmod 2\pi$ .
So
Conclusion.
Equivalently,
On the cuts. There atan in use treats an argument on its
own cut.
This identity is what the difference formula in section 5 is built on. It could also be used to compute gd directly; section 4 compares its accuracy with the form that is implemented.
For real
With
Where
Inside the strip
Outside the strip the two differ by a multiple of
Sala's eq. (2.11) gives, for
The implementation rewrites the real part as
and uses Sala's
(gd (z)
;; Eqn 2.11, with the real part written as atan2(sinh x, cos y)
(let ((x (realpart z))
(y (imagpart z)))
(complex (atan (sinh x) (cos y))
(atanh (* (sin y) (sech x))))))A possible improvement is to rewrite the imaginary part as
which avoids the cancellation in
Let
-
For real
$x$ ,$\mathrm{gd}(x) = \tan^{-1}(\sinh x) = \tan^{-1} s$ (section 3, real case). -
For real
$s \ne 0$ ,$\tan^{-1} s + \tan^{-1}(1/s) = \mathrm{sign}(s),\pi/2$ , and$\mathrm{sign}(s) = \mathrm{sign}(x)$ . Since$\mathrm{csch}, x = 1/s$ ,\alpha = \mathrm{sign}(s)\frac{\pi}{2} - \tan^{-1}\frac{c}{s}. -
For
$s \ne 0$ , the two-argument arctangent is\mathrm{atan2}(s, c) = \begin{cases} \frac{\pi}{2} - \tan^{-1}\frac{c}{s}, & s > 0 \quad (\text{values in } (0, \pi)), \\ -\frac{\pi}{2} - \tan^{-1}\frac{c}{s}, & s < 0 \quad (\text{values in } (-\pi, 0)), \end{cases}which is
$\mathrm{sign}(s),\pi/2 - \tan^{-1}(c/s)$ in both cases.
Therefore
At $x = 0$. Sala's formula divides by zero at
-
$\cos y > 0$ :$\mathrm{atan2}(0, \cos y) = 0$ , matching Sala's$x = 0$ case. -
$\cos y < 0$ : the point lies on a cut. atan2 gives$\pi$ , which is the limit from$x > 0$ . With IEEE signed zeros,$x = -0.0$ gives$-\pi$ , the limit from$x < 0$ . So the side of the cut is chosen explicitly, unlike in the$2\tan^{-1}(\tanh(u/2))$ form.
The atan2 form also avoids the cancellation in Sala's form for small
Sala's
From
using
The sum under the square root has no cancellation. It is zero only at
In double precision bf-jacobi-am the reduction of section 6.1 keeps the arguments small
enough that these limits are not reached.
The
(gd (z)
(let* ((x (realpart z))
(y (imagpart z))
(sx (sinh x))
(cy (cos y))
(big (max (abs sx) (abs cy)))
(small (min (abs sx) (abs cy))))
(complex (atan sx cy)
(asinh (/ (sin y)
(* big (sqrt (+ 1 (expt (/ small big) 2)))))))))Double precision, compared with a 50-digit reference evaluated at the same
double inputs, so this measures the algorithm's error and not the
conditioning of gd. 20,000 random points with
| form | worst rel. error, real | worst rel. error, imag |
|---|---|---|
| atan2 + Sala's |
|
|
| atan2 + |
In both of the first two rows, the worst cases are near the branch points.
The
With
Sala's series for the amplitude is
For
Derivation. Let
-
By section 2,
$\tan(\mathrm{gd}(u)/2) = \tanh(u/2)$ . So with$\alpha = \mathrm{gd}(A + w)/2$ and$\beta = \mathrm{gd}(A - w)/2$ ,\tan\alpha = \tanh a, \qquad \tan\beta = \tanh b, \qquad \frac{D}{2} = \alpha - \beta. -
Tangent subtraction, an algebraic identity valid for complex values:
\tan\frac{D}{2} = \frac{\tanh a - \tanh b}{1 + \tanh a \tanh b}. -
Multiply the numerator and denominator by
$\cosh a \cosh b$ :\begin{aligned} \text{numerator:} &\quad \sinh a \cosh b - \cosh a \sinh b = \sinh(a - b) = \sinh w, \\ \text{denominator:} &\quad \cosh a \cosh b + \sinh a \sinh b = \cosh(a + b) = \cosh A, \end{aligned}so
\tan\frac{D}{2} = \frac{\sinh w}{\cosh A}. -
Step 3 determines
$D/2$ only modulo$\pi$ . The branch is fixed in the next subsection.
Check at $A = 0$. The identity gives
Let
For real bf-jacobi-am is also called with complex
bf-jacobi-am uses the single test
which implies both:
Real $A$ and real $w$. gd takes values in
Complex $w$. Follow the path
- (a)
$\zeta(t) = \sinh(tw)/\cosh A$ stays off the cuts$\pm i[1, \infty)$ of$\tan^{-1}$ , and - (b)
$A + tw$ and$A - tw$ stay off the cuts of gd.
If both hold, the two sides agree along the whole path, and in particular at
Condition (a). For complex
and
Condition (b), for real $A \ge 0$. A point
The condition
-
The derivative of
$\sinh^{-1}(\cosh A)$ is$\sinh A / \sqrt{\cosh^2 A + 1} < 1$ , so$\sinh^{-1}(\cosh A) \le A + \sinh^{-1} 1$ , with$\sinh^{-1} 1 \approx 0.8814$ . Then$\left[\sinh^{-1}(\cosh A)\right]^2 - A^2 \le 2 \cdot 0.8814,A + 0.7768$ , which is below$\pi^2/4 \approx 2.4674$ for$A < 0.95$ . -
For
$A \ge 0.95$ , use$\sqrt{C^2 + 1} \le C + 1/(2C)$ with$C = \cosh A$ :\sinh^{-1}(\cosh A) - A \le \ln\left(1 + e^{-2A} + \frac{1}{e^{2A} + 1}\right) \le 2e^{-2A} =: \delta,so
$\left[\sinh^{-1}(\cosh A)\right]^2 - A^2 \le \delta(2A + \delta)$ . At$A = 0.95$ this is about$0.66$ , and it decreases for larger$A$ .
So condition (b) holds whenever condition (a) does, for real
Condition (b), for complex $A$. The argument above assumes
so
Example where the second test is needed. Take
and take
Both satisfy
The gd-difference value is the one consistent with Mathematica's branch
cuts. The line
In double precision with
| quantity | value | rel. error |
|---|---|---|
| 1.471304342110472 | ||
| 1.4713043401239134 | ||
| difference | 1.9865584732770003e−9 | |
| 1.9865585483886647e−9 | ||
| exact | 1.986558548388664…e−9 |
Each gd value carries an absolute error of about
digits. Every factor of 10 decrease in
Outside the region where the tests hold, principal
am has no cuts there. At
With
-
$m = 1$ .$\mathrm{am}(z|1) = \mathrm{gd}(z)$ (DLMF 22.16.5).$K(1)$ is infinite, so the series cannot be used. -
$1 - m$ rounds to$1$ ($\lvert m\rvert$ below about$1.1 \times 10^{-16}$ for doubles, or about$2^{-\text{fpprec}}$ for bigfloats, with fpprec in bits).$K' = K(1)$ cannot be computed. Use the nome series (6.3) with$q = m/16$ , which is the nome to working precision. -
Otherwise, reduce
$z$ by a multiple of$2K$ (6.1), then use the nome series if it converges faster than Sala's series (6.4), and Sala's series otherwise.
Sala's series is the bilateral sum
for every
bf-jacobi-am computes
so the reduced
-
$\sinh$ and$\cosh$ never overflow in double precision. Without the reduction,$\mathrm{gd}(A + w)$ needs$\sinh$ at up to about$2\lvert\mathrm{Re}, w\rvert$ , which overflows for$z \gtrsim 420$ at$m = 0.5$ . - The multiple of
$\pi$ is added once, instead of accumulating over$r$ terms each close to$\pi$ . - Fewer terms are needed. Before the series' terms start to decay,
$n$ must reach about$\lvert w\rvert/\lvert c\rvert$ , which is at most about$1$ after the reduction. For$z = 100$ ,$m = 0.5$ in double precision this is 13 terms instead of 38.
Truncation, not rounding. Truncating toward zero keeps the reduced
Effect on accuracy. The reduced argument
Let
So
- Complex
$m$ off the cuts$(-\infty, 0]$ and$[1, \infty)$ :$\mathrm{Im}, \tau > 0$ is the standard property of the map from$m$ to$\tau$ . - Real
$m < 0$ :$K$ is real and positive, and$\mathrm{Im}, \tau = \mathrm{Re}, K' / K$ with$\mathrm{Re}, K(x) > 0$ for real$x > 1$ on either side of its cut. - Real
$m > 1$ :$K'$ is real and positive, and$\mathrm{Im}, \tau = K' \mathrm{Re}, K / \lvert K\rvert^2$ with$\mathrm{Re}, K(m) = K(1/m)/\sqrt{m} > 0$ . -
$0 < m < 1$ :$c$ is real and positive.
So the reduction, which divides by
For
with
Since
The series converges for
At
After the reduction, Sala's terms decay like bf-jacobi-am uses the nome series when
- For real
$z$ and real$0 < m < 1$ this is$K < K'$ , i.e.$m < 1/2$ . - A nonzero
$\mathrm{Im}, z$ moves the switch toward smaller$m$ , since it uses up the strip where the nome series converges. -
$\rho < 1$ is implied, so the nome series is never used where it diverges. -
$\mathrm{Im}(z/K)$ is unchanged by the reduction, so the test can use either$z$ .
Terms needed at
| nome series | Sala's series (approx.) | |
|---|---|---|
| 8 | 62 | |
| 3 | 167 | |
| 2 | ( |
|
| 1 |
Sections 7.4 and 7.5 and the
Without the reduction of 6.1, for real
With the reduction, Maxima under SBCL in double precision, against 60-digit
references at the same inputs (
| result | error | |
|---|---|---|
| 100 | 84.70311272411384 | +0.84 ulp |
| 1000 | 847.1374038213263 | −0.56 ulp |
| 3000 | 2541.6555265646302 | −0.47 ulp |
The unreduced series overflows for
Maxima under SBCL, with the previous bf-jacobi-am (Sala's series only)
and the current one. References are 50-digit values at the same inputs;
times are per call.
Double precision:
| call | correct value | before | after |
|---|---|---|---|
jacobi_am(0.5, 1e-20) |
0.5 | error: elliptic_kc(1) is undefined | 0.5 |
jacobi_am(10.0, 1e-3) |
9.997613139826175… | 9.997613139826168 (4 ulps), 84 µs | 9.997613139826175 (correctly rounded), 56 µs |
jacobi_am(3.0, 1e-10) |
2.99999999992150731… | 2.999999999921508 (1.6 ulps), 144 µs | 2.9999999999215072 (correctly rounded), 66 µs |
jacobi_am(0.5, 1e-15) |
0.49999999999999998… (rounds to 0.5) | 0.5, 132 µs | 0.5000000000000001 (1 ulp), 48 µs |
Bigfloat with fpprec = 32:
| call | correct value to 32 digits | before | after |
|---|---|---|---|
jacobi_am(3b0, 1b-30) |
2.9999999999999999999999999999992 | 2.9999999999999999999999999999996 (4 in the last digit), 40.9 ms | 2.9999999999999999999999999999992, 1.1 ms |
jacobi_am(10b0, 1b-3) |
9.9976131398261754702124306920947 | 9.9976131398261754702124306920951 (4 in the last digit), 6.4 ms | 9.9976131398261754702124306920948 (1 in the last digit), 1.2 ms |
jacobi_am(3b0, 1b-40) |
3.0 | error: elliptic_kc(1) is undefined | 3.0 |
The gains come from three places:
-
Tiny
$m$ no longer fails. When$1 - m$ rounds to$1$ , the previous code called$K(1)$ . -
Fewer terms. For small
$m$ , Sala's terms decay like$e^{-n\mathrm{Re}, c}$ with$\mathrm{Re}, c \approx 0.38$ at$m = 10^{-10}$ , while the nome series decays like$q^n$ with$q \approx m/16$ . -
Less accumulated rounding at larger
$z$ . At$z = 10$ the previous code summed about four terms of size$\pi$ ; the current code reduces$z$ and adds$4\pi$ once.
It is not correctly rounded everywhere: at jacobi_am(0.5, 1e-15) the
rounding in computing
Even with am correct to a few ulps of the computation of
- The series computes
$w = \pi z/(2K')$ , whose relative error is about$\varepsilon$ . Since$d\mathrm{am}/dz = \mathrm{dn}(z)$ , this gives an error in am of about$\lvert z\rvert,\lvert\mathrm{dn}(z)\rvert,\varepsilon$ . Any method that scales$z$ by a period has this error. -
$\sin(\mathrm{am})$ changes with am at rate$\lvert\cos\mathrm{am}\rvert = \lvert\mathrm{cn}(z)\rvert$ .
So
the second term from the rounding of am itself. Both
Example:
| am | am error | |||
|---|---|---|---|---|
| 1 | 3.57 | |||
| 4 | 2.55 | |||
| 6 | 5.71 | |||
| 9 | 1.94 | |||
| 5 | 0.11 |
At closeto((sin(am) - sn)/sn, ...), would need less slack because the test
values reach
For
A&S 16.11 maps
so
The $2\pi N$ term. The log gives am only modulo
Example:
Check. 400 random points with real
Advantages.
Implementation notes.
- Real
$u$ :$\mathrm{am} = \mathrm{atan2}(\sqrt{\mu},\mathrm{sn}(v|\mu), \mathrm{dn}(v|\mu)) + 2\pi N$ . Since$\mathrm{dn}(v|\mu) > 0$ , the atan2 gives the continuous part directly. - Complex
$u$ : compute the real part of the log as an atan2 and the imaginary part,$-\log\lvert\mathrm{dn} + i\sqrt{\mu},\mathrm{sn}\rvert$ , with log1p, so that small am keeps its relative accuracy. - Complex
$m$ :$K(\mu)$ is complex, and whether$\mathrm{round}(\mathrm{Re}, v / 4K(\mu))$ is still the right crossing count has not been checked.
A&S 16.10 maps
so
For
All at 30–40 digits with mpmath, using Sala's definitions above:
-
$\mathrm{gd}(u)$ vs$2\tan^{-1}(\tanh(u/2))$ : 20,000 random points with$\lvert\mathrm{Re}, u\rvert \le 4$ ,$\lvert\mathrm{Im}, u\rvert \le 12$ ; largest difference$3 \times 10^{-27}$ . -
$\mathrm{gd}(u)$ vs$\tan^{-1}(\sinh u)$ on the same points: largest difference$\pi$ (wrong branch outside$\lvert\mathrm{Im}, u\rvert < \pi/2$ ). - Sala's
$\alpha$ vs$\mathrm{atan2}(\sinh x, \cos y)$ : 20,000 random points with$\lvert x\rvert \le 6$ ,$\lvert y\rvert \le 20$ ; largest difference$5 \times 10^{-41}$ . -
$\mathrm{gd}(A + w) - \mathrm{gd}(A - w)$ vs$2\tan^{-1}(\sinh w / \cosh A)$ : 20,000 random points with real$A \in [0.05, 6]$ and complex$w$ satisfying$\sinh\lvert w\rvert < \cosh A$ ; largest difference$1.6 \times 10^{-30}$ . - The same comparison with complex
$A \in [0, 3] \times [-6, 6],i$ and complex$w$ satisfying only$\sinh\lvert w\rvert < \lvert\cosh A\rvert$ : 3,862 of 100,000 points differed, all by$\pm 2\pi$ . With$\lvert\mathrm{Re}, w\rvert < \mathrm{Re}, A$ added: none. -
$\mathrm{am}(z|m)$ with both tests vs all terms as gd differences, and$\sin(\mathrm{am})$ ,$\cos(\mathrm{am})$ vs sn, cn: 1,500 random points with$z \in [-3, 3] \times [-3, 3],i$ and$m$ complex in$[-10, 10] \times [-10, 10],i$ , real in$[-20, 0]$ , or real in$[1, 20]$ ; largest relative difference$10^{-29}$ , largest sn/cn error$7 \times 10^{-28}$ . - The reduction by
$2K$ with the single test$\lvert w\rvert < \mathrm{Re}, A$ , vs the unreduced series with both tests: 1,500 random points with$\lvert\mathrm{Re}, z\rvert \le 60$ ,$\lvert\mathrm{Im}, z\rvert \le 4$ and$m$ complex, real negative, real above 1, or in$(0, 1)$ ; largest relative difference$5 \times 10^{-29}$ . - The nome series vs Sala's series, with
$q = \exp(-\pi K'/K)$ : 909 points with$m$ real in$\pm[10^{-30}, 0.1]$ or complex with$\lvert m\rvert \lesssim 0.3$ ,$\lvert\mathrm{Re}, z\rvert \le 30$ ,$\lvert\mathrm{Im}, z\rvert \le 3$ and$\rho < 0.5$ ; largest relative difference$7 \times 10^{-28}$ . - Double-precision accuracy of the three forms of gd: see section 4.
- Errors at large
$\lvert z\rvert$ , at small$m$ , in sin(am) vs sn tests, and the reciprocal-modulus check for$m > 1$ : see section 7.
Of bf-jacobi-am itself, in Maxima under SBCL 2.2.9:
- Double precision, 300 random points, against 40-digit references. Largest
$\lvert\text{error}\rvert / (\varepsilon \max(1, \lvert\mathrm{am}\rvert))$ by kind of$m$ : 3.9 for$m \in (0, 1)$ ; 2.6 for$m < 0$ ; 8.2 for$m > 1$ (including the spurious imaginary part of section 7.4); 2.9 for complex$m$ ; 2.1 for$\lvert m\rvert \in [10^{-25}, 10^{-2}]$ ; 3.1 for$m \in (0.05, 0.95)$ with$\lvert z\rvert$ up to 2000. - Bigfloat with fpprec = 40, 40 random points with
$\lvert\mathrm{Re}, z\rvert \le 300$ and$m$ as above or down to$10^{-60}$ : largest relative error$8 \times 10^{-40}$ . - rtest_elliptic, before and after the change: problems 229 and 278 fail
both times, since their tolerances were set under CMUCL. Problem 280
failed before and passes after. Problem 249, the
$z = 2ki$ ,$m = 1.75$ bigfloat sin(am) vs sn test, passed before and fails after: its largest difference went from below its 6.3091b−31 tolerance to 6.33b−31. -
run_testsuite()after the change: the only other failure is rtest5 problem 80,describe(sin), because this build has no documentation.