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
ITrigonometricFunctions<PreciseNumber> — no Sin, Cos, Tan, Asin, …
IPowerFunctions<PreciseNumber> — Pow exists as an instance method and falls back to double for non-integer exponents
IHyperbolicFunctions<PreciseNumber>
Two consequences. A caller cannot write an algorithm generically over INumber<T>plus any of these constraints and have PreciseNumber satisfy it. And more sharply: taking a square root today means Math.Sqrt(x.To<double>()), so a 50-digit number that takes one root is a 15-digit number wearing a 50-digit type, silently.
What already exists and should be reused rather than re-derived
ReduceSignificance(int significantDigits) is public and rounds half away from zero. Every series below needs it: multiplication is exact, so x^n for a 50-digit x carries 50n digits, and an un-truncated Taylor series grows quadratically in memory for no accuracy gain.
Divide(left, right, int significantDigits) establishes the precedent for a precision-taking overload sitting next to a default one. The new functions should follow it exactly rather than invent a second convention.
ktsu.Semantics.Quantities' internal StorageMath.Sqrt<T> already implements a type-generic Newton square root — double-seeded, scaled by powers of four for values outside double's range, throwing rather than returning an unconverged estimate. It is the algorithm the roots sub-issue wants, already tested. (Opening it up is ktsu-dev/Semantics — separate issue there.)
Design decisions that apply to all of the sub-issues
Precision contract. None of these interface members takes a precision argument, so each computes at MinimumDivisionPrecision (50), matching Divide. Alongside each, add an explicit (value, int significantDigits) overload, mirroring Divide.
Accuracy contract: faithful rounding, not correct rounding. The result is within 1 ulp at the requested precision. Correct rounding runs into the table-maker's dilemma and is not worth the cost here. Document that, and do not claim more than it.
Guard digits. Compute internally at significantDigits + 10, truncate every intermediate to that working precision with ReduceSignificance, and reduce once at the end.
Termination. Sum until a term's exponent falls more than the working precision below the accumulator's, then take one more term. Never a fixed iteration count; non-convergence is an ArithmeticException, following StorageMath's precedent.
Atan2 is not on ITrigonometricFunctions. It lives on IFloatingPointIeee754<T>, which PreciseNumber should not implement — it is not IEEE-754 and has no NaN or infinity. So Atan2 is a bespoke static, added in the trig sub-issue because SGP4 cannot be written without it.
Sub-issues, in dependency order
IRootFunctions<PreciseNumber> — no dependencies
IExponentialFunctions + ILogarithmicFunctions + IPowerFunctions — no dependencies; also fixes Pow's silent double fallback
ITrigonometricFunctions + Atan2 — depends on both of the above and on the constants issue
IHyperbolicFunctions is cheap once exp/log land and can follow later.
Acceptance for the set
Each function checked against published 50-digit reference values (√2, ln 2, sin 1, cos 1, e, …)
Identity tests at 50 digits: sin²x + cos²x = 1, Exp(Log(x)) = x, Sqrt(x)² = x, Atan2 in all four quadrants
Agreement with the double answer to 15 digits across a sweep — the cheap regression net
Tracking issue. Found while speccing an orbital-mechanics showcase (SGP4 propagation) that wants PreciseNumber as its reference arithmetic.
PreciseNumberdeclares: INumber<PreciseNumber>and stops there. It has none of:IRootFunctions<PreciseNumber>— noSqrt,Cbrt,RootN,HypotIExponentialFunctions<PreciseNumber>/ILogarithmicFunctions<PreciseNumber>ITrigonometricFunctions<PreciseNumber>— noSin,Cos,Tan,Asin, …IPowerFunctions<PreciseNumber>—Powexists as an instance method and falls back todoublefor non-integer exponentsIHyperbolicFunctions<PreciseNumber>Two consequences. A caller cannot write an algorithm generically over
INumber<T>plus any of these constraints and have PreciseNumber satisfy it. And more sharply: taking a square root today meansMath.Sqrt(x.To<double>()), so a 50-digit number that takes one root is a 15-digit number wearing a 50-digit type, silently.What already exists and should be reused rather than re-derived
ReduceSignificance(int significantDigits)is public and rounds half away from zero. Every series below needs it: multiplication is exact, sox^nfor a 50-digitxcarries 50n digits, and an un-truncated Taylor series grows quadratically in memory for no accuracy gain.Divide(left, right, int significantDigits)establishes the precedent for a precision-taking overload sitting next to a default one. The new functions should follow it exactly rather than invent a second convention.ktsu.Semantics.Quantities' internalStorageMath.Sqrt<T>already implements a type-generic Newton square root —double-seeded, scaled by powers of four for values outsidedouble's range, throwing rather than returning an unconverged estimate. It is the algorithm the roots sub-issue wants, already tested. (Opening it up is ktsu-dev/Semantics — separate issue there.)Design decisions that apply to all of the sub-issues
Precision contract. None of these interface members takes a precision argument, so each computes at
MinimumDivisionPrecision(50), matchingDivide. Alongside each, add an explicit(value, int significantDigits)overload, mirroringDivide.Accuracy contract: faithful rounding, not correct rounding. The result is within 1 ulp at the requested precision. Correct rounding runs into the table-maker's dilemma and is not worth the cost here. Document that, and do not claim more than it.
Guard digits. Compute internally at
significantDigits + 10, truncate every intermediate to that working precision withReduceSignificance, and reduce once at the end.Termination. Sum until a term's exponent falls more than the working precision below the accumulator's, then take one more term. Never a fixed iteration count; non-convergence is an
ArithmeticException, followingStorageMath's precedent.Atan2is not onITrigonometricFunctions. It lives onIFloatingPointIeee754<T>, which PreciseNumber should not implement — it is not IEEE-754 and has no NaN or infinity. SoAtan2is a bespoke static, added in the trig sub-issue because SGP4 cannot be written without it.Sub-issues, in dependency order
IRootFunctions<PreciseNumber>— no dependenciesIExponentialFunctions+ILogarithmicFunctions+IPowerFunctions— no dependencies; also fixesPow's silentdoublefallbackITrigonometricFunctions+Atan2— depends on both of the above and on the constants issueIHyperbolicFunctionsis cheap once exp/log land and can follow later.Acceptance for the set
sin²x + cos²x = 1,Exp(Log(x)) = x,Sqrt(x)² = x,Atan2in all four quadrantsdoubleanswer to 15 digits across a sweep — the cheap regression netPreciseNumber.Benchmarks, parameterised by the repo'sDigitsaxis (8 / 30 / 200) with allocation reported, so the cost of each is on the record before it ships. Related: Investigate benchmark regressions in Max, CompareTo, ReduceSignificance, Pow, and Divide since 2.0 #76.