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
-46
View File
@@ -1,46 +0,0 @@
namespace Just.PreciseMath;
public static partial class DDMath
{
/// <inheritdoc cref="DoubleDouble.Exp"/>
[Pure]
public static DoubleDouble Exp(DoubleDouble value)
{
return DoubleDouble.Exp(value);
}
/// <inheritdoc cref="DoubleDouble.Exp2"/>
[Pure]
public static DoubleDouble Exp2(DoubleDouble value)
{
return DoubleDouble.Exp2(value);
}
/// <inheritdoc cref="DoubleDouble.Exp10"/>
[Pure]
public static DoubleDouble Exp10(DoubleDouble value)
{
return DoubleDouble.Exp10(value);
}
/// <inheritdoc cref="DoubleDouble.ExpM1"/>
[Pure]
public static DoubleDouble ExpM1(DoubleDouble value)
{
return DoubleDouble.ExpM1(value);
}
/// <inheritdoc cref="DoubleDouble.Exp2M1"/>
[Pure]
public static DoubleDouble Exp2M1(DoubleDouble value)
{
return DoubleDouble.Exp2M1(value);
}
/// <inheritdoc cref="DoubleDouble.Exp10M1"/>
[Pure]
public static DoubleDouble Exp10M1(DoubleDouble value)
{
return DoubleDouble.Exp10M1(value);
}
}
-70
View File
@@ -1,70 +0,0 @@
namespace Just.PreciseMath;
/// <summary>Provides mathematical functions for normalized double-double values.</summary>
/// <remarks>Results use fixed-size double-double precision, not arbitrary precision.</remarks>
public static partial class DDMath
{
/// <summary>Returns the absolute value without discarding the low component.</summary>
/// <remarks>Both signs of zero become positive zero; NaN is canonicalized and either infinity becomes positive infinity.</remarks>
[Pure]
public static DoubleDouble Abs(DoubleDouble value)
{
return DoubleDouble.Abs(value);
}
/// <inheritdoc cref="DoubleDouble.Square"/>
[Pure]
public static DoubleDouble Square(DoubleDouble value)
{
return DoubleDouble.Square(value);
}
/// <inheritdoc cref="DoubleDouble.Reciprocal"/>
[Pure]
public static DoubleDouble Reciprocal(DoubleDouble value)
{
return DoubleDouble.Reciprocal(value);
}
/// <inheritdoc cref="DoubleDouble.Cbrt"/>
[Pure]
public static DoubleDouble Cbrt(DoubleDouble value)
{
return DoubleDouble.Cbrt(value);
}
/// <inheritdoc cref="DoubleDouble.Hypot(DoubleDouble, DoubleDouble)"/>
[Pure]
public static DoubleDouble Hypot(DoubleDouble x, DoubleDouble y)
{
return DoubleDouble.Hypot(x, y);
}
/// <inheritdoc cref="DoubleDouble.Hypot(DoubleDouble, DoubleDouble, DoubleDouble)"/>
[Pure]
public static DoubleDouble Hypot(DoubleDouble x, DoubleDouble y, DoubleDouble z)
{
return DoubleDouble.Hypot(x, y, z);
}
/// <inheritdoc cref="DoubleDouble.RootN"/>
[Pure]
public static DoubleDouble RootN(DoubleDouble value, int n)
{
return DoubleDouble.RootN(value, n);
}
/// <inheritdoc cref="DoubleDouble.Sqrt"/>
[Pure]
public static DoubleDouble Sqrt(DoubleDouble value)
{
return DoubleDouble.Sqrt(value);
}
/// <inheritdoc cref="DoubleDouble.InvSqrt"/>
[Pure]
public static DoubleDouble InvSqrt(DoubleDouble value)
{
return DoubleDouble.InvSqrt(value);
}
}
@@ -44,13 +44,13 @@ public readonly partial struct DoubleDouble :
}
/// <summary>Returns the operand unchanged.</summary>
public static DoubleDouble operator +(DoubleDouble value)
public static DoubleDouble Plus(DoubleDouble value)
{
return value;
}
/// <summary>Negates the value, including the high zero's sign, retaining canonical NaN and zero residuals.</summary>
public static DoubleDouble operator -(DoubleDouble value)
public static DoubleDouble Negate(DoubleDouble value)
{
// Negation preserves normalization; only NaN and zero residuals need canonicalization.
return new DoubleDouble(double.IsNaN(value._high) ? double.NaN : -value._high,
@@ -58,7 +58,7 @@ public readonly partial struct DoubleDouble :
}
/// <summary>Adds normalized expansions, retaining low-sum residuals under cancellation.</summary>
public static DoubleDouble operator +(DoubleDouble left, DoubleDouble right)
public static DoubleDouble Add(DoubleDouble left, DoubleDouble right)
{
if (!IsFinite(left) || !IsFinite(right) || (left._high == 0.0 && right._high == 0.0))
{
@@ -73,7 +73,7 @@ public readonly partial struct DoubleDouble :
}
/// <summary>Subtracts normalized expansions.</summary>
public static DoubleDouble operator -(DoubleDouble left, DoubleDouble right)
public static DoubleDouble Subtract(DoubleDouble left, DoubleDouble right)
{
if (!IsFinite(left) || !IsFinite(right) || (left._high == 0.0 && right._high == 0.0))
{
@@ -95,7 +95,7 @@ public readonly partial struct DoubleDouble :
/// Swapping operands preserves both result components bit-for-bit.
/// Results are approximate double-double values, not universally correctly rounded.
/// </remarks>
public static DoubleDouble operator *(DoubleDouble left, DoubleDouble right)
public static DoubleDouble Multiply(DoubleDouble left, DoubleDouble right)
{
if (!IsFinite(left) || !IsFinite(right) || left._high == 0.0 || right._high == 0.0)
{
@@ -127,7 +127,7 @@ public readonly partial struct DoubleDouble :
/// <summary>Divides expansions using a quotient estimate and two residual corrections.</summary>
/// <remarks>Zero and nonfinite operands follow binary64 rules; precision decreases near underflow.</remarks>
public static DoubleDouble operator /(DoubleDouble left, DoubleDouble right)
public static DoubleDouble Divide(DoubleDouble left, DoubleDouble right)
{
if (!IsFinite(left) || !IsFinite(right) || left._high == 0.0 || right._high == 0.0)
{
@@ -159,35 +159,35 @@ public readonly partial struct DoubleDouble :
/// <summary>Applies the expansion operation without discarding the low component.</summary>
/// <remarks>Preserves the component bits of addition with the equivalent zero-low scalar expansion.</remarks>
public static DoubleDouble operator +(DoubleDouble left, double right)
public static DoubleDouble Add(DoubleDouble left, double right)
{
return PreciseMathHelper.AddScalar(left._high, left._low, right);
}
/// <summary>Applies the expansion operation without discarding the low component.</summary>
/// <remarks>Preserves the component bits of addition with the equivalent zero-low scalar expansion.</remarks>
public static DoubleDouble operator +(double left, DoubleDouble right)
public static DoubleDouble Add(double left, DoubleDouble right)
{
return right + left;
return Add(right, left);
}
/// <summary>Applies the expansion operation without discarding the low component.</summary>
/// <remarks>Preserves the component bits of subtraction with the equivalent zero-low scalar expansion.</remarks>
public static DoubleDouble operator -(DoubleDouble left, double right)
public static DoubleDouble Subtract(DoubleDouble left, double right)
{
return PreciseMathHelper.AddScalar(left._high, left._low, -right);
}
/// <summary>Applies the expansion operation without discarding the low component.</summary>
/// <remarks>Preserves the component bits of subtraction with the equivalent zero-low scalar expansion.</remarks>
public static DoubleDouble operator -(double left, DoubleDouble right)
public static DoubleDouble Subtract(double left, DoubleDouble right)
{
// Negate the components, not the result: exact cancellation must yield +0.
return PreciseMathHelper.AddScalar(-right._high, -right._low, left);
}
/// <summary>Applies the expansion operation without discarding the low component.</summary>
public static DoubleDouble operator *(DoubleDouble left, double right)
public static DoubleDouble Multiply(DoubleDouble left, double right)
{
if (!IsFinite(left) || !double.IsFinite(right) || left._high == 0.0 || right == 0.0)
{
@@ -207,14 +207,14 @@ public readonly partial struct DoubleDouble :
}
/// <summary>Applies the expansion operation without discarding the low component.</summary>
public static DoubleDouble operator *(double left, DoubleDouble right)
public static DoubleDouble Multiply(double left, DoubleDouble right)
{
return right * left;
return Multiply(right, left);
}
/// <summary>Divides by a scalar using a quotient estimate and two residual corrections.</summary>
/// <remarks>Preserves the component bits of division by the equivalent zero-low expansion.</remarks>
public static DoubleDouble operator /(DoubleDouble left, double right)
public static DoubleDouble Divide(DoubleDouble left, double right)
{
if (!IsFinite(left) || !double.IsFinite(right) || left._high == 0.0 || right == 0.0)
{
@@ -246,7 +246,7 @@ public readonly partial struct DoubleDouble :
/// <summary>Divides a scalar using a quotient estimate and two residual corrections.</summary>
/// <remarks>Preserves the component bits of division with the equivalent zero-low numerator.</remarks>
public static DoubleDouble operator /(double left, DoubleDouble right)
public static DoubleDouble Divide(double left, DoubleDouble right)
{
if (!double.IsFinite(left) || !IsFinite(right) || left == 0.0 || right._high == 0.0)
{
@@ -1,6 +1,6 @@
namespace Just.PreciseMath;
public static partial class DDMath
public readonly partial struct DoubleDouble
{
/// <summary>Returns the natural logarithm of a double-double value.</summary>
/// <remarks>
@@ -17,7 +17,7 @@ public static partial class DDMath
{
if (double.IsNaN(value.High) || value.High < 0.0)
{
return DoubleDouble.NaN;
return NaN;
}
if (value.High == 0.0)
{
@@ -27,9 +27,9 @@ public static partial class DDMath
{
return value;
}
if (value == DoubleDouble.One)
if (value == One)
{
return DoubleDouble.Zero;
return Zero;
}
return LogPositiveFinite(value);
}
@@ -49,9 +49,9 @@ public static partial class DDMath
}
int exponent = Math.ILogB(value.High);
DoubleDouble mantissa = DoubleDouble.FromComponents(Math.ScaleB(value.High, -exponent),
DoubleDouble mantissa = FromComponents(Math.ScaleB(value.High, -exponent),
Math.ScaleB(value.Low, -exponent));
if (mantissa.High > DoubleDouble.Sqrt2.High)
if (mantissa.High > Sqrt2.High)
{
mantissa *= 0.5;
++exponent;
@@ -72,6 +72,6 @@ public static partial class DDMath
}
// log(m) = 2*atanh(t). The omitted series tail is bounded by
// 2*|t|^51/(51*(1-t^2)); rounding, not truncation, dominates.
return (sum * 2.0) + (DoubleDouble.Ln2 * exponent);
return (sum * 2.0) + (Ln2 * exponent);
}
}
@@ -86,18 +86,6 @@ public readonly partial struct DoubleDouble
return IsNaN(y) ? x : MinMagnitude(x, y);
}
/// <summary>Adds one using double-double arithmetic, including its overflow and nonfinite behavior.</summary>
public static DoubleDouble operator ++(DoubleDouble value)
{
return value + 1.0;
}
/// <summary>Subtracts one using double-double arithmetic, including its overflow and nonfinite behavior.</summary>
public static DoubleDouble operator --(DoubleDouble value)
{
return value - 1.0;
}
/// <summary>Tests normalization and canonical NaN and zero-residual bit patterns.</summary>
public static bool IsCanonical(DoubleDouble value)
{
@@ -0,0 +1,100 @@
namespace Just.PreciseMath;
public readonly partial struct DoubleDouble
{
/// <inheritdoc cref="Plus"/>
public static DoubleDouble operator +(DoubleDouble value)
{
return Plus(value);
}
/// <inheritdoc cref="Negate"/>
public static DoubleDouble operator -(DoubleDouble value)
{
return Negate(value);
}
/// <inheritdoc cref="Add(DoubleDouble, DoubleDouble)"/>
public static DoubleDouble operator +(DoubleDouble left, DoubleDouble right)
{
return Add(left, right);
}
/// <inheritdoc cref="Subtract(DoubleDouble, DoubleDouble)"/>
public static DoubleDouble operator -(DoubleDouble left, DoubleDouble right)
{
return Subtract(left, right);
}
/// <inheritdoc cref="Multiply(DoubleDouble, DoubleDouble)"/>
public static DoubleDouble operator *(DoubleDouble left, DoubleDouble right)
{
return Multiply(left, right);
}
/// <inheritdoc cref="Divide(DoubleDouble, DoubleDouble)"/>
public static DoubleDouble operator /(DoubleDouble left, DoubleDouble right)
{
return Divide(left, right);
}
/// <inheritdoc cref="Add(DoubleDouble, double)"/>
public static DoubleDouble operator +(DoubleDouble left, double right)
{
return Add(left, right);
}
/// <inheritdoc cref="Add(double, DoubleDouble)"/>
public static DoubleDouble operator +(double left, DoubleDouble right)
{
return Add(left, right);
}
/// <inheritdoc cref="Subtract(DoubleDouble, double)"/>
public static DoubleDouble operator -(DoubleDouble left, double right)
{
return Subtract(left, right);
}
/// <inheritdoc cref="Subtract(double, DoubleDouble)"/>
public static DoubleDouble operator -(double left, DoubleDouble right)
{
return Subtract(left, right);
}
/// <inheritdoc cref="Multiply(DoubleDouble, double)"/>
public static DoubleDouble operator *(DoubleDouble left, double right)
{
return Multiply(left, right);
}
/// <inheritdoc cref="Multiply(double, DoubleDouble)"/>
public static DoubleDouble operator *(double left, DoubleDouble right)
{
return Multiply(left, right);
}
/// <inheritdoc cref="Divide(DoubleDouble, double)"/>
public static DoubleDouble operator /(DoubleDouble left, double right)
{
return Divide(left, right);
}
/// <inheritdoc cref="Divide(double, DoubleDouble)"/>
public static DoubleDouble operator /(double left, DoubleDouble right)
{
return Divide(left, right);
}
/// <summary>Adds one using double-double arithmetic, including its overflow and nonfinite behavior.</summary>
public static DoubleDouble operator ++(DoubleDouble value)
{
return Add(value, 1.0);
}
/// <summary>Subtracts one using double-double arithmetic, including its overflow and nonfinite behavior.</summary>
public static DoubleDouble operator --(DoubleDouble value)
{
return Subtract(value, 1.0);
}
}
@@ -1,6 +1,6 @@
namespace Just.PreciseMath;
public static partial class DDMath
public readonly partial struct DoubleDouble
{
/// <summary>Raises a double-double value to an integer power.</summary>
/// <remarks>
@@ -21,11 +21,11 @@ public static partial class DDMath
{
if (exponent == 0)
{
return DoubleDouble.One;
return One;
}
if (double.IsNaN(value.High))
{
return DoubleDouble.NaN;
return NaN;
}
if (exponent == 1)
{
@@ -43,10 +43,10 @@ public static partial class DDMath
// Widen BEFORE negation: abs(int.MinValue) is not an int.
long remaining = exponent < 0 ? -(long)exponent : exponent;
long factorExponent = Math.ILogB(value.High);
DoubleDouble factor = DoubleDouble.FromComponents(
DoubleDouble factor = FromComponents(
Math.ScaleB(Math.Abs(value.High), -(int)factorExponent),
Math.ScaleB(value.High < 0.0 ? -value.Low : value.Low, -(int)factorExponent));
DoubleDouble result = DoubleDouble.One;
DoubleDouble result = One;
long resultExponent = 0;
while (remaining != 0)
{
@@ -105,35 +105,35 @@ public static partial class DDMath
[Pure]
public static DoubleDouble Pow(DoubleDouble value, DoubleDouble exponent)
{
if (DoubleDouble.IsZero(exponent) || value == DoubleDouble.One)
if (IsZero(exponent) || value == One)
{
return DoubleDouble.One;
return One;
}
if (DoubleDouble.IsNaN(value) || DoubleDouble.IsNaN(exponent))
if (IsNaN(value) || IsNaN(exponent))
{
return DoubleDouble.NaN;
return NaN;
}
DoubleDouble magnitude = DoubleDouble.Abs(value);
if (DoubleDouble.IsInfinity(exponent))
DoubleDouble magnitude = Abs(value);
if (IsInfinity(exponent))
{
if (magnitude == DoubleDouble.One)
if (magnitude == One)
{
return DoubleDouble.One;
return One;
}
bool grows = (magnitude > DoubleDouble.One) == (exponent.High > 0.0);
return grows ? new DoubleDouble(double.PositiveInfinity) : DoubleDouble.Zero;
bool grows = (magnitude > One) == (exponent.High > 0.0);
return grows ? new DoubleDouble(double.PositiveInfinity) : Zero;
}
bool integer = DoubleDouble.IsInteger(exponent);
bool integer = IsInteger(exponent);
if (integer && exponent.High >= int.MinValue && exponent.High <= int.MaxValue)
{
// A normalized integer in this range has a zero low component.
// Reuse the integer algorithm, including exact identities and ties.
return Pow(value, (int)exponent.High);
}
bool negative = double.IsNegative(value.High) && DoubleDouble.IsOddInteger(exponent);
if (value.High == 0.0 || DoubleDouble.IsInfinity(value))
bool negative = double.IsNegative(value.High) && IsOddInteger(exponent);
if (value.High == 0.0 || IsInfinity(value))
{
bool infinite = (value.High == 0.0) == (exponent.High < 0.0);
double result = infinite ? double.PositiveInfinity : 0.0;
@@ -141,11 +141,11 @@ public static partial class DDMath
}
if (value.High < 0.0 && !integer)
{
return DoubleDouble.NaN;
return NaN;
}
if (magnitude == DoubleDouble.One)
if (magnitude == One)
{
return negative ? DoubleDouble.NegativeOne : DoubleDouble.One;
return negative ? NegativeOne : One;
}
DoubleDouble resultMagnitude = Exp(exponent * LogPositiveFinite(magnitude));
return negative ? -resultMagnitude : resultMagnitude;
@@ -158,7 +158,7 @@ public static partial class DDMath
// int.MinValue times any finite input's binary64 exponent.
int adjustment = Math.ILogB(value.High);
exponent += adjustment;
return DoubleDouble.FromComponents(Math.ScaleB(value.High, -adjustment),
return FromComponents(Math.ScaleB(value.High, -adjustment),
Math.ScaleB(value.Low, -adjustment));
}
}
@@ -200,7 +200,7 @@ public readonly partial struct DoubleDouble : IRootFunctions<DoubleDouble>
case 1:
return value;
case -1:
return DDMath.Reciprocal(value);
return Reciprocal(value);
case 2:
return Sqrt(value);
case -2:
@@ -0,0 +1,128 @@
namespace Just.PreciseMath;
/// <summary>Provides instance-style calls to the static DoubleDouble mathematical functions.</summary>
/// <remarks>
/// Every extension returns a new result without modifying its receiver. Extensions
/// forward directly to DoubleDouble, retaining its numerical and special-value contracts.
/// </remarks>
public static class DoubleDoubleExtensions
{
/// <inheritdoc cref="DoubleDouble.Abs(DoubleDouble)"/>
[Pure]
public static DoubleDouble Abs(this DoubleDouble value)
{
return DoubleDouble.Abs(value);
}
/// <inheritdoc cref="DoubleDouble.Square(DoubleDouble)"/>
[Pure]
public static DoubleDouble Square(this DoubleDouble value)
{
return DoubleDouble.Square(value);
}
/// <inheritdoc cref="DoubleDouble.Reciprocal(DoubleDouble)"/>
[Pure]
public static DoubleDouble Reciprocal(this DoubleDouble value)
{
return DoubleDouble.Reciprocal(value);
}
/// <inheritdoc cref="DoubleDouble.Sqrt(DoubleDouble)"/>
[Pure]
public static DoubleDouble Sqrt(this DoubleDouble value)
{
return DoubleDouble.Sqrt(value);
}
/// <inheritdoc cref="DoubleDouble.InvSqrt(DoubleDouble)"/>
[Pure]
public static DoubleDouble InvSqrt(this DoubleDouble value)
{
return DoubleDouble.InvSqrt(value);
}
/// <inheritdoc cref="DoubleDouble.Cbrt(DoubleDouble)"/>
[Pure]
public static DoubleDouble Cbrt(this DoubleDouble value)
{
return DoubleDouble.Cbrt(value);
}
/// <inheritdoc cref="DoubleDouble.Exp(DoubleDouble)"/>
[Pure]
public static DoubleDouble Exp(this DoubleDouble value)
{
return DoubleDouble.Exp(value);
}
/// <inheritdoc cref="DoubleDouble.Exp2(DoubleDouble)"/>
[Pure]
public static DoubleDouble Exp2(this DoubleDouble value)
{
return DoubleDouble.Exp2(value);
}
/// <inheritdoc cref="DoubleDouble.Exp10(DoubleDouble)"/>
[Pure]
public static DoubleDouble Exp10(this DoubleDouble value)
{
return DoubleDouble.Exp10(value);
}
/// <inheritdoc cref="DoubleDouble.ExpM1(DoubleDouble)"/>
[Pure]
public static DoubleDouble ExpM1(this DoubleDouble value)
{
return DoubleDouble.ExpM1(value);
}
/// <inheritdoc cref="DoubleDouble.Exp2M1(DoubleDouble)"/>
[Pure]
public static DoubleDouble Exp2M1(this DoubleDouble value)
{
return DoubleDouble.Exp2M1(value);
}
/// <inheritdoc cref="DoubleDouble.Exp10M1(DoubleDouble)"/>
[Pure]
public static DoubleDouble Exp10M1(this DoubleDouble value)
{
return DoubleDouble.Exp10M1(value);
}
/// <inheritdoc cref="DoubleDouble.Log(DoubleDouble)"/>
[Pure]
public static DoubleDouble Log(this DoubleDouble value)
{
return DoubleDouble.Log(value);
}
/// <inheritdoc cref="DoubleDouble.RootN(DoubleDouble, int)"/>
[Pure]
public static DoubleDouble RootN(this DoubleDouble value, int n)
{
return DoubleDouble.RootN(value, n);
}
/// <inheritdoc cref="DoubleDouble.Pow(DoubleDouble, int)"/>
[Pure]
public static DoubleDouble Pow(this DoubleDouble value, int exponent)
{
return DoubleDouble.Pow(value, exponent);
}
/// <inheritdoc cref="DoubleDouble.Pow(DoubleDouble, double)"/>
[Pure]
public static DoubleDouble Pow(this DoubleDouble value, double exponent)
{
return DoubleDouble.Pow(value, exponent);
}
/// <inheritdoc cref="DoubleDouble.Pow(DoubleDouble, DoubleDouble)"/>
[Pure]
public static DoubleDouble Pow(this DoubleDouble value, DoubleDouble exponent)
{
return DoubleDouble.Pow(value, exponent);
}
}