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/SinCos/Tan at default precision throw ArgumentOutOfRangeException on the library's own constants (e.g. Sin(PreciseNumber.Pi)) #124
The overloads that take no precision (Sin(x), Cos(x), SinCos(x), Tan(x), in PreciseNumber/PreciseNumber.Trigonometry.cs:101-102, 129-130, 157-158, 220-221) use DefaultTrigonometricPrecision(x) (line 736), which returns max(x.SignificantDigits, 50).
The built-in constants carry ConstantPrecision (150) digits and have one integer digit. For them the default asks for 150 digits, and reducing a one-integer-digit argument to 150 digits needs π to 151 digits. RequireReducibleArgument then throws. In other words, the overload that picks its own precision picks one it will refuse.
This contradicts two pieces of documentation:
The XML docs for these overloads promise the result is "produced to the significant digits of x" and list no ArgumentOutOfRangeException.
The remark on DefaultTrigonometricPrecision says it exists so that a constant carrying ConstantPrecision digits is handled.
Reproduction
Sin(PreciseNumber.Pi) → ArgumentOutOfRangeException: Reducing an argument of 1 integer digits to 150 significant digits needs π to 151 digits, but it is stored to 150. At most 149 …
Cos(Pi), Cos(Tau), Sin(E), SinCos(Pi) → same exception
Sin(Ln2) → works (0 integer digits)
Exp(Pi), Log(Pi), Pow(Pi, E), Sinh(Pi), Atan(Pi), Atan2(Pi, E), Asin(Pi/4) → all work at 150 digits
The same exception is thrown for any computed value that has at least 150 significant digits and at least one integer digit, for example a quotient or root of two constants.
Why it matters
Math.Sin(Math.PI)-style code is the most basic use of the API, and every other transcendental function handles these inputs. Callers can't predict which values will throw without knowing the internal ceiling on π digits.
Suggested fix
In the default-precision overloads only, clamp the precision to what can be delivered: Math.Min(DefaultTrigonometricPrecision(x), ConstantPrecision - IntegerDigitCount(x)), with a floor of 1.
Keep throwing only when even the clamped value is impossible, such as 1e200, which the existing refusal test already pins.
Priority: High. Sin(PreciseNumber.Pi), Cos(Tau) and SinCos(Pi) throw ArgumentOutOfRangeException through the overloads that are meant to choose their own precision. That is the most basic use of the trig API, and the XML docs promise it works. Every other transcendental function handles the same inputs.
Area / suggested assignee:DefaultTrigonometricPrecision and the default-precision overloads in PreciseNumber/PreciseNumber.Trigonometry.cs. Owner: @matt-edmondson
Next step: in the default-precision overloads only, clamp the precision to ConstantPrecision - IntegerDigitCount(x) with a floor of 1, and keep the explicit overloads strict. Add tests that Sin(Pi), Cos(Tau), SinCos(Pi) and Tan(Pi / 4) return values.
Activity
matt-edmondson commentedon Sep 27, 2026
Triage
Sin(PreciseNumber.Pi),Cos(Tau)andSinCos(Pi)throwArgumentOutOfRangeExceptionthrough the overloads that are meant to choose their own precision. That is the most basic use of the trig API, and the XML docs promise it works. Every other transcendental function handles the same inputs.DefaultTrigonometricPrecisionand the default-precision overloads inPreciseNumber/PreciseNumber.Trigonometry.cs. Owner: @matt-edmondsonTan's guard digits lower its ceiling further), which touches the same code, so land them together or land this one first. No open PR covers it.ConstantPrecision - IntegerDigitCount(x)with a floor of 1, and keep the explicit overloads strict. Add tests thatSin(Pi),Cos(Tau),SinCos(Pi)andTan(Pi / 4)return values.Generated by Claude Code