Skip to content

Sin, Cos, Tan, Cot, Sec, Csc: precision from the condition number, as in WMA - #2054

Merged
tombouctou merged 5 commits into
masterfrom
trig-real-valued-precision
Oct 19, 2026
Merged

tombouctou merged 5 commits into
masterfrom
trig-real-valued-precision

Conversation

@tombouctou

@tombouctou tombouctou commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Part of step 6 of the outline in #2047. On top of #2053 (#2052, #2051): this diff is against #2053's branch.

Sin, Cos, Tan, Cot, Sec, Csc get their precision from the condition number Abs[x f'[x] / f[x]], as WMA does. Each function only adds its condition_numbers (see #2052). Where f[x] is small, the formula uses the value already computed, so the digits lost near a zero are measured at full precision.

Input before this PR WMA 15
Precision[Sin[1.5`20]] 20. 20.9732 20.9732
Precision[Sin[100.`20]] 20. 17.7688 17.7688
Precision[Sin[3.14159265358979`20]] 20. 5.01319 5.01319
Precision[Cos[1.5`20]] 20. 18.6746 18.6746
Precision[Tan[100.`20]] 20. 17.6401 17.6401
Precision[Sec[0.3`20]] 20. 21.0324 21.0324

Zeros (added in review)

As in WMA 15. An exact zero stays exact (Precision[Sin[0]] is Infinity), and a result that cancels to zero keeps an accuracy (Accuracy[Sin[N[Pi, 20]]] is 19.5029); both were already right. Fixed here:

  • An inexact zero argument has an absolute error only. Its error in the result is how much f changes within 10^-accuracy of 0: Sin[020]is020 (was 015), and Cos[020] is 1 with precision 40.301 (was 20.). This is in the shared helper from Power, Sqrt: precision from the condition number, as in WMA #2052. It takes the smaller change of the two sides, so a jump at 0, as ArcCot has, does not count. It applies to an accuracy of at least 1.
  • Cot and Csc of an inexact zero (0. or 020``) are ComplexInfinity. They stayed unevaluated.

Tests: test_trig_zero.

Tests

test_trig_real_valued_precision in test/builtin/atomic/test_numbers.py, with WMA 15 values at three points per function. 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

@rocky

rocky commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

Looks good, but please let's add type annotations for the new functions.

@tombouctou
tombouctou force-pushed the log-real-valued-precision branch from d6da960 to f7d8f32 Compare October 19, 2026 21:17
@tombouctou
tombouctou force-pushed the trig-real-valued-precision branch from 3e3ef84 to 866f038 Compare October 19, 2026 21:17
tombouctou and others added 2 commits October 20, 2026 01:18
Part of step 6 of #2047 (MATH-227), on top of the Log PR.

The relative error of x is multiplied by Abs[x f'[x] / f[x]], as in WMA:
x Cot[x] for Sin, x Tan[x] for Cos, x (1 + Tan[x]^2) / Tan[x] for Tan,
and so on. Where f[x] is small, the formula uses the value already
computed, so the loss near a zero is measured at full precision.

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>
@rocky

rocky commented Oct 19, 2026

Copy link
Copy Markdown
Member

Looks good, but please let's add type annotations for the new functions.

Thanks for handling this suggestion.

@tombouctou
tombouctou force-pushed the log-real-valued-precision branch from f7d8f32 to f4b3c83 Compare October 19, 2026 21:18
@tombouctou
tombouctou force-pushed the trig-real-valued-precision branch from 866f038 to 86dc366 Compare October 19, 2026 21:18
@tombouctou

Copy link
Copy Markdown
Collaborator Author

Thanks. Added in 86dc366: each condition_numbers takes (x: mpmath.mpf, value: mpmath.mpf) and returns tuple[mpmath.mpf]. They stay mpmath numbers rather than floats, so that a tiny factor does not underflow to 0. (see the reply on #2053). The same annotations are now in #2052 (the hook and Power), #2053, #2055 and #2056. mypy is clean on these files.

With #2051 merged, the stack is rebased onto master: #2052 is now against master, and each PR above it against the one below.

("Precision[Sec[1.5`20]]", "18.6746", None),
("Precision[Sec[0.3`20]]", "21.0324", None),
("Precision[Csc[1.5`20]]", "20.9732", None),
("Precision[Csc[100.`20]]", "17.7688", None),

@rocky rocky Oct 19, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to add checks for edge cases like when the numerator is 0?

In[1]:= Precision[Sin[0]]
Out[1]= Infinity

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I added the zero cases (c568255 and d4d90e4), checked against WMA 15:

Input before now WMA 15
Precision[Sin[0]] Infinity Infinity Infinity
Accuracy[Sin[N[Pi, 20]]] 19.5029 19.5029 19.5029
Accuracy[Sin[020]]`` 15. 20. 20.
Precision[Cos[020]]`` 20. 40.301 40.301
Cot[0.], Csc[0.] unevaluated ComplexInfinity ComplexInfinity
Cot[020], Csc[020] unevaluated ComplexInfinity ComplexInfinity

The first two were already right: an exact zero stays exact, and a result that cancels to zero keeps an accuracy. They are now tested.

The other two cases were wrong:

One case is left as it was: an inexact zero that gives a complex result, like ArcCosh[020]``. Complex results all still take the old path, and they are a separate item.

@rocky

rocky commented Oct 19, 2026

Copy link
Copy Markdown
Member

LGTM. Decide if you want to add the divide by 0 cases which report Infinity. Then feel free to merge.

tombouctou and others added 2 commits October 20, 2026 01:30
As asked in review: the edge cases where a value or an argument is zero.
An exact zero stays exact (Precision[Sin[0]] is Infinity), and a zero
result keeps its accuracy (Accuracy[Sin[N[Pi, 20]]] is 19.5029); both
were already right and are now tested. Two cases were not, as in WMA:

- An inexact zero argument has an absolute error but no relative one.
  Its error in the result is now the most that f changes within
  10^-accuracy of 0: Sin[0``20] is 0``20 (was 0``15), and Cos[0``20]
  is 1 with precision 40.301 (was 20.), since Cos changes by only
  (10^-20)^2 / 2. This applies to an accuracy of at least 1; on a wider
  interval looking at its ends would not bound f, so those keep the old
  path.
- Cot and Csc of an inexact zero (0. or 0``20) are ComplexInfinity, as
  Cot[0] already was. They stayed unevaluated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A branch cut at 0, as for ArcCot, jumps on one side: ArcCot[0``20]
would otherwise get the size of the jump as its error. Where the
function is continuous, the two sides agree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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 added a commit that referenced this pull request Oct 19, 2026
As suggested in review: where the formulas divide by Sqrt[1 - x^2] or by
the value. ArcSin[1.`20] raised ZeroDivisionError; with the fallback in
#2054 its error is how much it changes within the error of 1, as WMA
does for ArcCos[1.`20] (0``9.849) and for ArcSin just below 1. Also
0`20 (an exact 0) and 0.0`20 (a machine 0.).

WMA gives ArcSin[1.`20] and ArcCsc[1.`20] precision 20.1961, which does
not agree with its own ArcCos[1.`20] or ArcSin[0.9999999999999999999`20];
here they get 10.0456.

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. 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

Copy link
Copy Markdown
Collaborator Author

One more commit since your LGTM (78a0b39), from the edge cases you suggested on #2056:

  • Poles: Tan[N[Pi/2, 20]] and Tan[1.5707963`5] gave 0.`1.; they now give ComplexInfinity, as in WMA. Tan, Sec, Cot, Csc set has_poles.
  • Bounds: Sin[1.`20*^30] is 00``: when no digit is left, a bounded function has an error no larger than its bound. Sin and `Cos` set `value_bound = 1.0`.
  • Fallback where the condition factor does not exist (a division by zero, an infinite factor, or a value of 0): the error is how much the function changes within the error of its argument, as for a zero argument. This fixes the ZeroDivisionError that ArcSin[1.`20] raised in ArcSin, ArcCos, ArcTan, ArcCot, ArcSec, ArcCsc: precision from the condition number, as in WMA #2055.

All checked against WMA 15 and tested in test_trig_zero.

Base automatically changed from log-real-valued-precision to master October 19, 2026 22:32
@tombouctou
tombouctou merged commit 0a3b8ec into master Oct 19, 2026
9 checks passed
@tombouctou
tombouctou deleted the trig-real-valued-precision branch October 19, 2026 22:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants