Repository navigation
Hyperbolic functions and their inverses: precision from the condition number, as in WMA - #2056
Merged
Merged
Conversation
tombouctou
force-pushed
the
arctrig-real-valued-precision
branch
from
October 19, 2026 20:29
38d35ea to
a59edde
Compare
tombouctou
force-pushed
the
hyperbolic-real-valued-precision
branch
from
October 19, 2026 20:29
87d89dc to
5958913
Compare
tombouctou
force-pushed
the
arctrig-real-valued-precision
branch
from
October 19, 2026 21:17
a59edde to
c1efce4
Compare
tombouctou
force-pushed
the
hyperbolic-real-valued-precision
branch
from
October 19, 2026 21:17
5958913 to
79b3423
Compare
tombouctou
force-pushed
the
arctrig-real-valued-precision
branch
from
October 19, 2026 21:18
c1efce4 to
694522f
Compare
tombouctou
force-pushed
the
hyperbolic-real-valued-precision
branch
from
October 19, 2026 21:19
79b3423 to
6eb4ce9
Compare
This was referenced Oct 19, 2026
Member
|
LGTM - merge when you feel is ready. Decide if you want to add edge-case tests around exact zero / near-zero / pole-adjacent values, where formulas divide by value or by sqrt(1-x^2). |
tombouctou
force-pushed
the
arctrig-real-valued-precision
branch
from
October 19, 2026 21:49
694522f to
48907e4
Compare
tombouctou
force-pushed
the
hyperbolic-real-valued-precision
branch
from
October 19, 2026 21:49
6eb4ce9 to
77e79f6
Compare
… number Part of step 6 of #2047 (MATH-227), on top of the inverse trig PR. As in WMA, the relative error of x is multiplied by Abs[x f'[x] / f[x]]. For Tanh and Coth, WMA uses the condition number of Sinh[x] / Cosh[x], with both errors added, when Abs[x] < 1: Precision[Tanh[0.3`20]] is 19.9519, not 20.0258. This follows it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
As asked in review: mpmath numbers in and out, as for Power. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
As for Cot and Csc: Csch of an inexact zero is ComplexInfinity, as in WMA (Csch[0.] stayed unevaluated; Coth[0.] already had the rule). The hyperbolic functions of 0``20 get their error from how much they change near 0: Sinh[0``20] is 0``20, Cosh[0``20] is 1 with precision 40.301. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
As suggested in review. Coth and Csch set has_poles, and Tanh and Sech are bounded by 1 (see #2054). ArcCosh[1.`20] and ArcSech[1.`20] are 0``9.849, as in WMA, and the values next to 1 or to a pole are tested too, as are 0`20 (an exact 0) and 0.0`20 (a machine 0.). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tombouctou
added a commit
that referenced
this pull request
Oct 19, 2026
As suggested in review, edge cases next to poles and where the formulas divide by the value or by Sqrt[1 - x^2]. As in WMA: - Where the condition factor does not exist (a division by zero, an infinite factor, or a value of 0), the error is how much f changes within the error of its argument, as was already done for an inexact zero argument; a side where f has no real value is left out. This is what the inverse functions need at the ends of their domain (#2055, #2056), where ArcSin[1.`20] raised ZeroDivisionError. - A function with poles gives ComplexInfinity when no digit is left: Tan[N[Pi/2, 20]] and Tan[1.5707963`5] (was 0.`1.). Tan, Sec, Cot and Csc set has_poles. - A bounded function has an error no larger than its bound: Sin[1.`20*^30] is 0``0. Sin and Cos set value_bound. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tombouctou
force-pushed
the
arctrig-real-valued-precision
branch
from
October 19, 2026 22:04
48907e4 to
58715b3
Compare
tombouctou
force-pushed
the
hyperbolic-real-valued-precision
branch
from
October 19, 2026 22:04
77e79f6 to
03d2771
Compare
Collaborator
Author
|
Thanks, added (03d2771, with the shared part in #2054), checked against WMA 15:
Left as it was: |
tombouctou
added a commit
that referenced
this pull request
Oct 20, 2026
…n WMA (#2063) A follow-up to #2056 (part of #2047). `ArcTanh` and `ArcCoth` have poles at 1 and -1. For an inexact argument there, SymPy gave `Infinity`. Near a pole, the old path gave `0.` or a complex number even when the argument's error covered the pole. In WMA, if the error of an inexact argument covers a pole, the result is `Indeterminate`: within that error, the function goes to `Infinity` on one side and takes an imaginary part on the other. A machine number has no error, so only `1.` and `-1.` themselves are covered. Exact `ArcTanh[1]` is still `Infinity`. This is a new `MPMathFunction` attribute, `indeterminate_at`, checked by `covers_point` in `mathics/eval/numeric.py`. | Input | master | this PR | WMA 15 | |---|---|---|---| | ``ArcTanh[1.`20]`` | `Infinity` | `Indeterminate` | `Indeterminate` | | `ArcTanh[-1.]` | `-Infinity` | `Indeterminate` | `Indeterminate` | | `ArcCoth[1.]` | `Infinity` | `Indeterminate` | `Indeterminate` | | ``ArcTanh[1.0000001`5]`` | `Infinity` | `Indeterminate` | `Indeterminate` | | ``ArcTanh[0.9999999`5]`` | `0.` | `Indeterminate` | `Indeterminate` | | ``ArcTanh[1.000001`6]`` | `7.27805 - 1.5708 I` | `Indeterminate` | `Indeterminate` | | ``Precision[ArcTanh[0.999999`6.1]]`` | `1.26163` | `1.26163` | `1.26163` | | `ArcTanh[1]` | `Infinity` | `Infinity` | `Infinity` | Right at the boundary, WMA gives ``ArcTanh[0.999999`6]`` = ``0``-6.``, which looks like an artifact. Here it is a number with precision about 1.16. ## Tests In `test_hyperbolic_real_valued_precision` (`test/builtin/atomic/test_numbers.py`), with WMA 15 values, plus a doctest in `ArcTanh`. Full run on kimmy next to master: all 4620 doctests pass. The pytest failures are the ones that depend on test order: each failing file passes when run on its own. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: R. Bernstein <rocky@users.noreply.github.com>
rocky
pushed a commit
that referenced
this pull request
Oct 26, 2026
The rest of #2047 step 6, for complex numbers: complex arithmetic, and functions with a complex value at a real argument, now get their precision the way WMA does. In WMA each part of a `Complex` keeps its own error. `Accuracy` combines the two errors in quadrature, and `Precision` is that accuracy plus `Log10` of the modulus; an exact part also counts toward the modulus. Before this PR, Mathics3 gave a complex result the precision of its least precise input, or machine precision, which is why ``1.5`20.3 + 2.5`20.3 I`` had precision 15. - `Plus` and `Times` on complex numbers with exact or `PrecisionReal` parts work out each part with the real rules. `Times` multiplies as a balanced tree and squares a pair of equal factors. `z^n` squares starting from the top bit of `n`, and `1/z` is `(a - b I)/(a^2 + b^2)`. This is the order WMA uses, and it changes the last digits of the precision. ``2.`20 I`` keeps an exact zero real part. - A function with a complex value at a real argument (``ArcSin[2.`20]``, ``Log[-1.`20]``, ``ArcCosh[0``20]``, ``ArcSec[0.5`20]``, …) gives each part the error from that part of `x f'[x]`, as #2052–#2056 do for real values. A part that does not change gets `2^-54` of the error, so the `Pi` part of ``Log[-1.`20]`` is 16 digits more precise than the real part, as in WMA. At a zero or a branch point, the change of `f` within the error goes to the nonzero parts. - A negative `PrecisionReal` to a `Rational` power: `x^(1/q)` shares the error of the whole value between its parts, and `x^(p/q)` is `x^n (x^(1/q))^r`. Checked against WMA for `p/q` from −5/2 to 7/3. - `Log[x]` is no longer rewritten as `Log[E, x]`: the numerified `E` base added an error of its own. - An inexact zero real part is now shown, as in WMA (``0``19.4 + 2.`19.7 I``). `N[I, 30]` is ``1.`30 I``. | Input | master | this PR | WMA 15 | |---|---|---|---| | ``Precision[ArcSec[0.5`20]]`` | `15.1196` | `20.0571` | `20.0571` | | ``Precision[1.5`20.3 + 2.5`20.3 I]`` | `15.` | `20.3` | `20.3` | | ``ArcCosh[0``20]`` | ``1.5707963…`20.*I`` | ``1.5707963…`20.1961*I`` | ``1.5707963…`20.1961*I`` | | ``Sqrt[-2.`20]`` | ``1.4142135…`20.*I`` | ``1.4142135…`20.301*I`` | ``1.4142135…`20.301*I`` | | ``Precision[Log[-1.`20]]`` | `15.4971` | `20.4971` | `20.4971` | | ``Accuracy[Im[Log[-1.`20]]] - Accuracy[Re[Log[-1.`20]]]`` | `4.50285` | `16.2556` | `16.2556` | | ``Precision[(1.`20 + 2.`25 I) (3.`22 - 1.`18 I)]`` | `15.` | `18.4939` | `18.4939` | | ``Precision[(1.`20 + 2.`25 I)^5]`` | `15.` | `19.3049` | `19.3049` | | ``Precision[(-8.`20)^(1/3)]`` | `20.` | `20.4771` | `20.4771` | Not in this PR: functions of a complex argument (``Sqrt[1.`20 + I]``, ``Exp[1.`20 I]``), a negative base with an inexact exponent, and `N` of an exact complex number with two nonzero parts, where WMA splits the precision between the parts. ## Tests `test_complex_precision` and `test_complex_valued_precision` in `test/builtin/atomic/test_numbers.py`, next to `test_real_valued_precision`, with WMA 15 values. Full run on kimmy: all doctests pass. pytest under xdist (`-n 4`) fails a different handful of tests on each run, on master as well, because those tests depend on symbols that earlier tests in the same worker define or clear (`f`, `F`, `x`). With `--dist loadfile`, master fails 15 (`test_forms.py`, `test_options.py`, `test_testing_expressions.py`, `test_latex.py`) and this branch fails 7 (`test_list.py`, `test_diffeqns.py`, `test_constructing.py`). None of them is about numbers, and each of these files passes when run on its own. Benchmark from #2050 on kimmy, best of 5, ms: | Case | master | this PR | |---|---|---| | ``Total[Table[N[1/k, 50], {k, 2000}]]`` | 2645 | 2738 | | ``Times @@ Table[N[1 + 1/k, 50], {k, 2000}]`` | 3255 | 3324 | | ``Do[x = N[k, 50] + Pi, {k, 2000}]`` | 5388 | 5238 | | ``Total[Table[1./k, {k, 2000}]]`` | 1988 | 2056 | | ``Total[Table[N[1/k + I/(k+1), 50], {k, 2000}]]`` | 4884 | 5127 | | ``Times @@ Table[N[1 + I/k, 50], {k, 500}]`` | 883 | 1070 | | ``Table[N[1 + I/k, 30]^5, {k, 500}]`` | 1435 | 1820 | | ``Table[1 / N[1 + I/k, 30], {k, 500}]`` | 1592 | 1670 | | ``Table[ArcSin[N[1 + k, 30]], {k, 500}]`` | 1112 | 1504 | | ``Table[Log[N[-k, 30]], {k, 500}]`` | 1421 | 1322 | The real cases are unchanged within noise. Complex `Times`, `z^5` and `ArcSin` outside its domain are 20–35% slower: their parts are now computed from real operations, and `ArcSin` takes more derivatives. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of step 6 of the outline in #2047. On top of the inverse trigonometric PR, #2055: this diff is against its branch.
The hyperbolic functions and their inverses get their precision from the condition number
Abs[x f'[x] / f[x]], as WMA does.One WMA detail: for
TanhandCothwithAbs[x] < 1, WMA uses the condition number ofSinh[x] / Cosh[x]with both errors added,x (Tanh[x] + Coth[x]). FromAbs[x] >= 1on it uses the true one. I checked at 0.05, 0.3, 0.5, 0.9, 0.99, 1., 1.01, 1.1, 1.2, 1.4, 2. and 5.; the switch is exactly at 1. This PR follows it, soPrecision[Tanh[0.3`20]]is19.9519, as in WMA, not20.0258. For largex,x (1 - Tanh[x]^2) / Tanh[x]would cancel, so it is computed as2 x / Sinh[2 x].Precision[Sinh[25.`20]]20.18.602118.6021Precision[Tanh[0.3`20]]20.19.951919.9519Precision[Tanh[25.`20]]20.39.714739.7147Precision[ArcTanh[0.99`20]]20.18.725918.7259Precision[ArcSech[0.99`20]]20.18.301818.3018Zeros
With the rule from #2054 for an inexact zero argument, as in WMA 15:
Sinh,Tanh,ArcSinhandArcTanhof020are020, andCosh[020]andSech[020]are 1 with precision40.301.Cschof0.or020`` is nowComplexInfinity, as `Coth[0.]` already was; it stayed unevaluated. Tested in `test_hyperbolic_real_valued_precision`.Tests
test_hyperbolic_real_valued_precisionintest/builtin/atomic/test_numbers.py, with WMA 15 values. Full run on kimmy: doctests all pass. The pytest failures are the ones that depend on the order the tests run in; the failing files that touch numbers pass on their own.🤖 Generated with Claude Code