Skip to content

Take an arccotangent at its jump from the side its argument arrives from - #2420

Merged
Rafael-SOWNet merged 1 commit into
masterfrom
feature/an-arccotangent-at-its-jump-is-taken-from-the-side
Nov 13, 2026
Merged

Rafael-SOWNet merged 1 commit into
masterfrom
feature/an-arccotangent-at-its-jump-is-taken-from-the-side

Conversation

@Rafael-SOWNet

@Rafael-SOWNet Rafael-SOWNet commented Nov 13, 2026 •

Copy link
Copy Markdown
Member

This library's arccotangent is arctan(1/t), with range (-pi/2, pi/2]: arccot(-0.001) is -1.5698, arccot(0) is pi/2 and arccot(0.001) is 1.5698. It jumps at 0. A limit read the value at 0, so arccot(x) at 0 was pi/2 from the left, where it is -pi/2, and pi/2 two-sided, where there is no limit. Quotients over it inherited the wrong sign.

Where the argument arrives at 0, the arccotangent is now answered from the sign it arrives with: pi/2 from above, -pi/2 from below. A two-sided limit has a value only when both sides arrive with the same sign. Substitution and the paths that take a factor out no longer read the value at the jump. SitsOnAJump now names the arccotangent's jump next to sgn's.

Input, at 0 side 2.6.0 master this branch
arccot(x) left pi/2 pi/2 -pi/2
arccot(x) right pi/2 pi/2 pi/2
arccot(x) both pi/2 pi/2 NaN
arccot(-x^2) both pi/2 pi/2 -pi/2
arccot(x) + arctan(x) both pi/2 pi/2 NaN
arccot(x) / x left -oo -oo +oo
arccot(x) / x both NaN NaN +oo
x * arccot(x) / sin(x)^2 both NaN NaN +oo
(arccot(x) - pi/2) / x both -1 -1 NaN
(arccot(x) - pi/2) / x right -1 -1 -1
(arccot(x) + pi/2) / x left -oo -oo -1
arccot(x + 1) both pi/4 pi/4 pi/4
arccot(x * arccot(x)) left pi/2 pi/2 pi/2
sgn(x * arccot(x)) left unevaluated -1 1
sgn(x * arccot(x)) both unevaluated NaN 1
floor(x * arccot(x)) left unevaluated -1 0
1 / (x * arccot(x)) left -oo -oo unevaluated
arccot(x * sin(1/x)) both pi/2 pi/2 unevaluated
arccot((x^2 - 1) - (x - 1)(x + 1)) both pi/2 pi/2 pi/2

Each value on this branch follows from arccot(t) = pi/2 - t + O(t^3) for t -> 0+ and -pi/2 - t + O(t^3) for t -> 0-. The rows that changed are in BREAKING-CHANGES.md, and the new test pins them.

The sign of an expression that vanishes at the point was read from its first non-vanishing derivative there. Where that derivative holds arccot(x), putting 0 in reads the value at the jump, so x * arccot(x), which is positive on both sides of 0, came out negative from the left. On master that gave the wrong sgn and floor rows above. Once arccot was taken from the side, it also turned arccot(x * arccot(x)) into -pi/2. That reading now declines, and the sign is read from the factors instead. An argument that is 0 everywhere gets the constant pi/2. An independent review of this branch found these cases.

LimitTest.TestEquivalenceTableTo0 pinned (arccot(x) - pi/2) / x at 0, two-sided, as -1. That holds only for the textbook (0, pi) range. Under this library's range the left side is +oo, so the row moves to the new test as one-sided cases.

Checked on this branch:

  • Tests: UnitTests 19348 passed; one improper-integral test hit its 5-minute wall-clock cap while the machine was loaded and passes alone in 27 s, plus the MCP, Terminal, InteractiveWrapper and F# wrapper suites, and the AOT smoke test.
  • Harnesses: BoundCheck, RootCheck, CasBench, PropCheck, SimpSweep, RuleCheck, CanonCheck and Confluence all pass.
  • limitcheck at DEPTH=3, COUNT=600, on 42 seeds against master: no answer changed. Three rows moved under load, on seeds 16, 31 and 77: one now runs past the 5 s cap and another no longer does. On a quiet machine each gives the same answer, in the same time, on master and on this branch.

🤖 Generated with Claude Code

@codecov

codecov Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 74.07407% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.80%. Comparing base (6d5f175) to head (447c0b4).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...nctions/Continuous/Limits/Solvers/Limit.Classes.cs 73.33% 1 Missing and 3 partials ⚠️
...ath/Functions/Continuous/Limits/Transformations.cs 77.77% 0 Missing and 2 partials ⚠️
...nctions/Continuous/Limits/Solvers/Limit.Solvers.cs 66.66% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2420      +/-   ##
==========================================
- Coverage   86.82%   86.80%   -0.02%     
==========================================
  Files         312      312              
  Lines       69523    69545      +22     
  Branches    20305    20312       +7     
==========================================
+ Hits        60360    60366       +6     
- Misses       4930     4942      +12     
- Partials     4233     4237       +4     
Flag Coverage Δ
cpp 37.77% <ø> (ø)
csharp 87.34% <74.07%> (-0.02%) ⬇️
fsharp 32.97% <ø> (ø)
interactive 39.81% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...nctions/Continuous/Limits/Solvers/Limit.Solvers.cs 87.34% <66.66%> (-0.39%) ⬇️
...ath/Functions/Continuous/Limits/Transformations.cs 88.83% <77.77%> (-0.03%) ⬇️
...nctions/Continuous/Limits/Solvers/Limit.Classes.cs 76.95% <73.33%> (-0.49%) ⬇️

... and 10 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

The library's arccotangent is arctan(1/t), with range (-pi/2, pi/2]:
arccot(-0.001) = -1.5698, arccot(0) = pi/2, arccot(0.001) = 1.5698. It
jumps at 0, and a limit read the value there, so arccot(x) at 0 was pi/2
from the left, where it is -pi/2, and pi/2 two-sided, where no limit
exists. A quotient over it inherited the wrong sign: arccot(x)/x from the
left was -oo, where it is +oo.

Where the argument arrives at 0, the arccotangent is now answered from the
sign its argument arrives with: pi/2 from above, -pi/2 from below, and
nothing two-sided unless both sides arrive with the same sign. Substitution
and the factor-taking-out paths no longer read the value at the jump, and
SitsOnAJump names the arccotangent's jump alongside sgn's.

(arccot(x) - pi/2)/x at 0 two-sided was pinned as -1 in LimitTest, which
holds for the (0, pi) convention only; under this library's range its left
side is +oo. The case moves to the new test as one-sided rows.

The sign of an expression vanishing at the point was read from its first
non-vanishing derivative there. Where that derivative holds an arccotangent
at its jump, putting the point in reads the jump's value, so x arccot(x),
positive on both sides of 0, came out negative from the left; that reading
now declines and the factors are read instead. An argument that is 0
everywhere is answered with the constant pi/2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Rafael-SOWNet
Rafael-SOWNet force-pushed the feature/an-arccotangent-at-its-jump-is-taken-from-the-side branch from 806e47d to 447c0b4 Compare November 13, 2026 13:23
@Rafael-SOWNet
Rafael-SOWNet merged commit fe19c27 into master Nov 13, 2026
35 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in AngouriMath Nov 13, 2026
@Rafael-SOWNet
Rafael-SOWNet deleted the feature/an-arccotangent-at-its-jump-is-taken-from-the-side branch November 13, 2026 14:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant