You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Sin/Cos/Tan near a multiple of π/2 return wrong digits and the wrong sign: Sin(PiTo(60), 25) = -3.75e-46, correct is +4.59e-60 #156
SinCos (PreciseNumber/PreciseNumber.Trigonometry.cs ~L195–205) sizes π for the reduction as working + argumentDigits + TrigonometricGuardDigits. That budget covers the argument's integer digits only, not the leading digits that cancel when x lies close to q·π/2. The remainder x − q·π/2 carries an absolute error of about 10^-reductionDigits. When the true remainder is smaller than that, the series runs on rounding noise, and the result is reported as if it had digits correct significant digits. Cos and Tan share the path. SinPi is unaffected because it reduces exactly.
Repro
PiTo(n) below is π rounded to n significant digits. Correct values were computed with Python decimal at 120 digits and confirmed by the library itself at 100 digits.
Call
Returned
Correct
Sin(PiTo(60), 25)
-3.7510582097494e-46
4.592307816406286208998628e-60
Sin(PiTo(40), 10)
4.97115803e-31
1.693993751e-40
Cos(PiTo(60)/2, 25)
-1.8755291048747e-46
≈ 2.3e-60
Tan(PiTo(60), 25)
-2.506e-56
≈ 4.59e-60
Cos(1.57079632679489661923132169163975144, 20)
2.0986e-36 (5 digits)
2.0985846996875529104874…e-36
Asking for enough digits gives the right answer: Sin(PiTo(60), 100) returns 4.592307816406286208998628034…e-60. So the error comes from under-budgeted reduction, not from the series.
Why it matters
Evaluating sin or cos at a rounded π, π/2 or a multiple of either is the classic precision test, and it is exactly what a high-precision library is used for. The library returns a confidently wrong value with the wrong sign and a wrong magnitude. It raises no error, although CLAUDE.md's position on RequireReducibleArgument is that "every reported digit is correct". This is not #124, #125 or #143, which are about throwing at default precision, Tan's guard digits, and requests above ~140 digits.
Suggested fix / acceptance criteria
After reduction, measure the cancellation: how far |remainder| sits below the magnitude implied by x. When it exceeds the guard digits, redo the reduction with π widened by that many digits.
If the widened reduction would exceed ConstantPrecision, throw the same ArgumentOutOfRangeException that RequireReducibleArgument uses rather than returning noise.
Tests:
Sin(PiTo(60), 25) returns 4.592307816406286208998628e-60 or throws the documented exception, and never returns a wrong value.
The same holds for Cos(PiTo(60)/2, 25) and Tan(PiTo(60), 25).
Priority: High. Sin, Cos and Tan near multiples of π/2 return confidently wrong values, with the wrong sign and magnitude, and raise no error. This contradicts the documented "every reported digit is correct" contract.
Area / suggested assignment: Trigonometry argument reduction (SinCos in PreciseNumber.Trigonometry.cs).
Activity
matt-edmondson commentedon Oct 6, 2026
Triage
Sin,CosandTannear multiples of π/2 return confidently wrong values, with the wrong sign and magnitude, and raise no error. This contradicts the documented "every reported digit is correct" contract.SinCosinPreciseNumber.Trigonometry.cs).TrigonometricGuardDigits.ConstantPrecision. It touches a hot path, so check the benchmarks (see Investigate benchmark regressions in Max, CompareTo, ReduceSignificance, Pow, and Divide since 2.0 #76) after the change.Generated by Claude Code