operators refactoring
.NET Test / .NET tests (push) Successful in 2m11s

This commit is contained in:
2026-09-24 00:39:59 +04:00
parent 3de9457fdc
commit ac93744579
26 changed files with 651 additions and 334 deletions
+48 -21
View File
@@ -22,8 +22,11 @@ already-normalized results. Mathematical constants use precomputed high/low pair
checked against independently computed high-precision values; accessing them does
not perform double-double arithmetic or allocate on the heap.
- Arithmetic: unary `+`/`-`, binary `+`, `-`, `*`, `/`, and both operand orders with
a `double`. Addition retains residuals under cancellation; multiplication uses
- Arithmetic: static `Add`, `Subtract`, `Multiply`, and `Divide` methods accept
`DoubleDouble` pairs and both operand orders with a `double`. `Plus` and `Negate`
provide unary operations. The arithmetic operators (`+`, `-`, `*`, `/`, unary
`+`/`-`, and `++`/`--`) are thin wrappers around these methods.
Addition retains residuals under cancellation; multiplication uses
fused multiply-add; division uses residual corrections. Mixed `double` operators
use specialized scalar paths rather than promoting the scalar to `DoubleDouble`.
Division retains the complete first remainder and applies two quotient corrections,
@@ -92,7 +95,7 @@ DoubleDouble quarterTurn = DoubleDouble.PiOver2;
The factors avoid deriving constants at runtime; the multiplication itself remains
approximate DD arithmetic, so conversions are not guaranteed exact round trips.
The list is mathematical and dimensionless, not a table of unit-dependent physical
constants. The natural logarithm function is provided separately by `DDMath.Log`.
constants. The natural logarithm function is provided separately by `DoubleDouble.Log`.
## Mathematical functions
@@ -102,16 +105,40 @@ The additional `InvSqrt` helper and three-argument `Hypot` overload live alongsi
them. Exponential functions live in `DoubleDouble.ExponentialFunctions.cs`:
`Exp`, `Exp2`, `Exp10`, `ExpM1`, `Exp2M1`, and `Exp10M1` complete
`IExponentialFunctions<DoubleDouble>`, including cancellation-safe overrides of
the interface's default minus-one methods. `DDMath` exposes thin forwarding
wrappers for roots and exponentials; logarithm, power, and reciprocal kernels
remain in `DDMath`.
the interface's default minus-one methods. Natural logarithm and power kernels
live in `DoubleDouble.Log.cs` and `DoubleDouble.Pow.cs`; reciprocal lives in
`DoubleDouble.NumberBase.cs`. Arithmetic implementations live in
`DoubleDouble.Arithmetic.cs`, with forwarding operators in `DoubleDouble.Operators.cs`.
The `DDMath` static class provides:
All mathematical functions are static members of `DoubleDouble`. The former
`DDMath` facade has been removed: migrate `DDMath.Function(...)` calls to
`DoubleDouble.Function(...)`. This is a breaking API change; no compatibility
facade is provided.
`DoubleDoubleExtensions`, in the same `Just.PreciseMath` namespace, also provides
instance-style calls for `Abs`, `Square`, `Reciprocal`, `Sqrt`, `InvSqrt`, `Cbrt`,
all six exponential functions, `Log`, `RootN(int)`, and `Pow` with `int`, `double`,
or `DoubleDouble` exponents. These extensions return a result without modifying
the receiver and forward directly to the corresponding static method, preserving
its numerical contract and component bits. Arithmetic remains available through
operators and named static methods; `Hypot` remains a static multi-operand function.
```csharp
using Just.PreciseMath;
DoubleDouble value = new(-4.0);
DoubleDouble magnitude = value.Abs();
DoubleDouble inverse = value.Abs().Square().Sqrt().Reciprocal();
DoubleDouble power = magnitude.Pow(3);
DoubleDouble root = magnitude.RootN(2);
// value is still -4; inverse is 0.25.
```
`DoubleDouble` provides:
- `Abs(DoubleDouble)`: preserves both components, maps either signed zero to
positive zero and either infinity to positive infinity, and returns canonical NaN.
It shares the existing `DoubleDouble.Abs` implementation.
- `Square(DoubleDouble)`: forwards to the specialized `DoubleDouble.Square` kernel.
- `Square(DoubleDouble)`: uses a specialized double-double squaring kernel.
It combines the equal cross terms with FMA, normalizes, then incorporates the
low-component square without losing selected exactly representable tails.
Either signed zero maps to positive zero, either infinity to positive infinity,
@@ -216,17 +243,17 @@ 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);
DoubleDouble reciprocal = DoubleDouble.Reciprocal(new DoubleDouble(3.0));
DoubleDouble magnitude = DoubleDouble.Abs(-root);
DoubleDouble smallPower = DoubleDouble.Pow(new DoubleDouble(2.0), -1024);
DoubleDouble exponential = DoubleDouble.Exp(new DoubleDouble(1.0));
DoubleDouble binaryPower = DoubleDouble.Exp2(new DoubleDouble(-1000.0));
DoubleDouble decimalPower = DoubleDouble.Exp10(new DoubleDouble(0.5));
DoubleDouble tinyChange = DoubleDouble.ExpM1(new DoubleDouble(1e-30));
DoubleDouble logarithm = DDMath.Log(new DoubleDouble(10.0));
DoubleDouble fractionalPower = DDMath.Pow(new DoubleDouble(2.0), 0.5);
DoubleDouble logarithm = DoubleDouble.Log(new DoubleDouble(10.0));
DoubleDouble fractionalPower = DoubleDouble.Pow(new DoubleDouble(2.0), 0.5);
DoubleDouble preciseExponent = DoubleDouble.FromComponents(0.5, 1e-30);
DoubleDouble precisePower = DDMath.Pow(new DoubleDouble(2.0), preciseExponent);
DoubleDouble precisePower = DoubleDouble.Pow(new DoubleDouble(2.0), preciseExponent);
```
Reciprocal tests check bitwise equivalence with `1.0 / value` and independently
@@ -254,7 +281,7 @@ 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.
special-value signs 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
@@ -275,9 +302,9 @@ check `2^-100` relative error plus one minimum binary64 subnormal, with a separa
bounded reference-rounding allowance. The base-two/base-ten and minus-one fixtures
are checked at 450/650 digits, including adjacent lows at true range boundaries,
series transitions, and tiny inputs. Additional component checks pin sparse
base-two corrections; constrained generic calls and facade calls match direct
calls bit-for-bit. Integer-power tests use exact rational
references and high-precision fixtures for large exponents; their tested absolute
base-two corrections; constrained generic calls match direct calls bit-for-bit.
Integer-power tests use exact rational references and high-precision fixtures for
large exponents; their tested absolute
error bound is `|exact result| * (|exponent| + 1) * 2^-100 + 2^-1074`, not uniform
relative accuracy independent of the exponent. These functions are approximate;
precision decreases near underflow and approximation can affect results extremely
@@ -402,8 +429,8 @@ bool success = DoubleDouble.TryParse("1.25e-2".AsSpan(), CultureInfo.InvariantCu
## Deferred scope
Natural `DDMath.Log`, the complete exponential family on `DoubleDouble`, and all
three `DDMath.Pow` overloads are implemented.
Natural `DoubleDouble.Log`, the complete exponential family on `DoubleDouble`, and all
three `DoubleDouble.Pow` overloads are implemented.
Logarithms in other bases, generic-math interfaces beyond `ISignedNumber`,
`IFloatingPointConstants`, `IRootFunctions`, and `IExponentialFunctions`, additional text formats/shortest-
round-trip formatting, and non-arithmetic performance benchmarks remain deferred.