added root functions
.NET Test / .NET tests (push) Successful in 1m31s

This commit is contained in:
2026-09-16 20:24:08 +04:00
parent 24d2aef892
commit 7084fae174
11 changed files with 1912 additions and 94 deletions
+57 -5
View File
@@ -90,6 +90,12 @@ constants. The natural logarithm function is provided separately by `DDMath.Log`
## Mathematical functions
Root functions are implemented on `DoubleDouble` in `DoubleDouble.RootFunctions.cs`:
`Sqrt`, `Cbrt`, `Hypot`, and `RootN` complete `IRootFunctions<DoubleDouble>`.
The additional `InvSqrt` helper and three-argument `Hypot` overload live alongside
them. `DDMath` exposes thin forwarding wrappers; the other mathematical kernels
remain in `DDMath`.
The `DDMath` static class provides:
- `Abs(DoubleDouble)`: preserves both components, maps either signed zero to
@@ -112,6 +118,34 @@ The `DDMath` static class provides:
with FMA. Signed zeros map to correspondingly signed infinities; positive infinity
maps to positive zero; negative nonzero inputs and NaN return canonical NaN.
This is a dedicated algorithm, not a claim of measured speedup over `1.0 / Sqrt(x)`.
- `Cbrt(DoubleDouble)`: real cube root using a scaled binary64 seed and compensated
Newton corrections. Signed zeros and infinities are preserved; NaN is canonical.
An exponent-tracked low-component correction avoids losing representable sparse
residuals during scaling.
- `Hypot(DoubleDouble, DoubleDouble)`: computes `sqrt(x²+y²)` with bounded scaled
squares and complete-expansion rescaling at exponent boundaries. Widely separated
operands use a small correction without squaring an underflow-prone ratio.
Results are nonnegative, including positive zero. Either infinity takes precedence
over NaN; otherwise NaN propagates. At the upper boundary, exact squared-input
comparisons determine overflow; an overflowing approximation of a finite root
is clamped to the largest finite component pair. Overflow produces positive infinity.
- `Hypot(DoubleDouble, DoubleDouble, DoubleDouble)`: the 3D Euclidean norm
`sqrt(x²+y²+z²)`, with the same special-value and approximate-accuracy contracts.
Coordinates are ordered by magnitude before evaluating scaled squares, so signs
and permutations give identical component bits. Widely separated coordinates
contribute combined corrections without prematurely underflowing their squares.
A zero coordinate reduces to the two-argument overload; exact overflow checks
include all three original inputs. This overload is a convenience API, not an
additional member of `IRootFunctions`.
- `RootN(DoubleDouble, int)`: real nth root for positive degrees, reciprocal root
for negative degrees, supporting the complete `int` range. Degree zero always
returns NaN; negative nonzero inputs require an odd degree. Odd degrees retain
the input sign, while even degrees map either signed zero to positive zero for
positive degrees and positive infinity for negative degrees. Negative degrees
exchange zero and infinity. Unlike `Sqrt(-0)`, `RootN(-0, 2)` is positive zero.
Degrees ±1, ±2 and ±3 reuse identity/reciprocal and existing root kernels; other
degrees refine a binary64 seed using integer powers with separately tracked
exponents, then incorporate the input low without premature underflow.
- `Pow(DoubleDouble, int)`: exponentiation by squaring with a separately tracked
binary exponent. Supports the full `int` domain, including `int.MinValue`, and
reciprocates a bounded significand before final scaling for negative exponents.
@@ -138,8 +172,12 @@ The `DDMath` static class provides:
```csharp
using Just.PreciseMath;
DoubleDouble root = DDMath.Sqrt(new DoubleDouble(2.0));
DoubleDouble inverseRoot = DDMath.InvSqrt(new DoubleDouble(2.0));
DoubleDouble root = DoubleDouble.Sqrt(new DoubleDouble(2.0));
DoubleDouble inverseRoot = DoubleDouble.InvSqrt(new DoubleDouble(2.0));
DoubleDouble cubeRoot = DoubleDouble.Cbrt(new DoubleDouble(-8.0));
DoubleDouble distance = DoubleDouble.Hypot(new DoubleDouble(3.0), new DoubleDouble(4.0));
DoubleDouble norm3D = DoubleDouble.Hypot(new DoubleDouble(2.0), new DoubleDouble(3.0), new DoubleDouble(6.0));
DoubleDouble fifthRoot = DoubleDouble.RootN(new DoubleDouble(2.0), 5);
DoubleDouble reciprocal = DDMath.Reciprocal(new DoubleDouble(3.0));
DoubleDouble magnitude = DDMath.Abs(-root);
DoubleDouble smallPower = DDMath.Pow(new DoubleDouble(2.0), -1024);
@@ -165,6 +203,20 @@ both suites exercise half-ulp low-component normalization boundaries.
This is a tested approximate-accuracy contract, not exhaustive coverage
of all component pairs or a guarantee of correctly rounded results.
Cube-root and nth-root tests check `2^-100` relative error for finite nonzero
inputs with degree magnitude at least two. Small degrees use exact integer-power
inequalities; large degrees use independently generated decimal references checked
at 450 and 650 digits, including `int.MinValue` and `int.MaxValue`.
`RootN(x, -1)` retains the reciprocal contract, including its subnormal error floor.
Hypotenuse tests use exact squared inequalities with `2^-100` relative error plus
one minimum binary64 subnormal. Tests also check exact binary cases, sparse lows,
special-value signs, facade component-bit agreement, and constrained generic dispatch.
The 2D and 3D hypotenuse overflow tests bracket the exact threshold, including scaled
55/48/73 and 1/2/2/3 Pythagorean cases at the midpoint. Three-coordinate tests include
all signs and permutations of boundary cases and sparse corrections, including
corrections that only become representable when combined. Finite components remain approximate,
not universally correctly rounded, including near underflow.
Logarithm tests compare exact component sums with independently generated
120-digit decimal references, requiring agreement at 450 and 650 digits. They
check `2^-100` relative error plus one minimum binary64 subnormal, with an explicit
@@ -291,9 +343,9 @@ bool success = DoubleDouble.TryParse("1.25e-2".AsSpan(), CultureInfo.InvariantCu
## Deferred scope
Natural `DDMath.Log`, `Exp`, and all three `Pow` overloads are implemented.
Logarithms in other bases, generic-math interfaces beyond `ISignedNumber` and
`IFloatingPointConstants`, additional text formats/general round-trip formatting,
and non-arithmetic performance benchmarks remain deferred.
Logarithms in other bases, generic-math interfaces beyond `ISignedNumber`,
`IFloatingPointConstants`, and `IRootFunctions`, additional text formats/general
round-trip formatting, and non-arithmetic performance benchmarks remain deferred.
Replacing allocating arithmetic boundary fallbacks is also deferred; the current
`BigInteger` paths remain in place. That optimization does not require removing
`BigInteger` from conversions, parsing, formatting, or independent test oracles.