This commit is contained in:
@@ -55,6 +55,59 @@ public static partial class DDMath
|
||||
return DoubleDouble.FromComponents(Math.ScaleB(root.High, rootExponent), Math.ScaleB(root.Low, rootExponent));
|
||||
}
|
||||
|
||||
/// <summary>Returns the reciprocal square root with double-double precision.</summary>
|
||||
/// <remarks>
|
||||
/// Uses power-of-two scaling and a compensated Newton step without double-double
|
||||
/// division. Results are approximate, not guaranteed correctly rounded; positive
|
||||
/// finite inputs are tested against a relative error bound of 2^-100 across the
|
||||
/// binary64 range. Positive/negative zero maps to positive/negative infinity,
|
||||
/// positive infinity to positive zero, and negative nonzero values or NaN to
|
||||
/// canonical NaN.
|
||||
/// </remarks>
|
||||
[Pure]
|
||||
public static DoubleDouble InvSqrt(DoubleDouble value)
|
||||
{
|
||||
if (double.IsNaN(value.High) || value.High < 0.0)
|
||||
{
|
||||
return DoubleDouble.NaN;
|
||||
}
|
||||
if (value.High == 0.0)
|
||||
{
|
||||
return new DoubleDouble(Math.CopySign(double.PositiveInfinity, value.High));
|
||||
}
|
||||
if (double.IsPositiveInfinity(value.High))
|
||||
{
|
||||
return DoubleDouble.Zero;
|
||||
}
|
||||
|
||||
// As in Sqrt, the even exponent is in [-1074, 1022], high is in [1, 4),
|
||||
// and any underflow in a sparse scaled low is below the error bound.
|
||||
int exponent = Math.ILogB(value.High) & ~1;
|
||||
double high = Math.ScaleB(value.High, -exponent);
|
||||
double low = Math.ScaleB(value.Low, -exponent);
|
||||
double estimate = 1.0 / Math.Sqrt(high);
|
||||
|
||||
// With u=2^-53, the seed has O(u) relative error. Preserve the square's
|
||||
// FMA residual before cancellation in 1 - (high + low)*estimate^2:
|
||||
// using only the rounded square would leave O(u) error after refinement.
|
||||
// All leading products are bounded and normal. Omitting low*squareError
|
||||
// contributes only O(u^2), as does one Newton step's remaining error.
|
||||
double square = estimate * estimate;
|
||||
double squareError = Math.FusedMultiplyAdd(estimate, estimate, -square);
|
||||
double residual = Math.FusedMultiplyAdd(-high, square, 1.0);
|
||||
residual = Math.FusedMultiplyAdd(-high, squareError, residual);
|
||||
residual = Math.FusedMultiplyAdd(-low, square, residual);
|
||||
double correction = (0.5 * estimate) * residual;
|
||||
DoubleDouble inverseRoot = DoubleDouble.FromComponents(estimate, correction);
|
||||
|
||||
// The result high is normal and finite over the entire positive input
|
||||
// range. Rescale in the opposite direction to Sqrt and canonicalize any
|
||||
// zero low, including underflow of an exceptionally sparse correction.
|
||||
int inverseExponent = -(exponent / 2);
|
||||
return DoubleDouble.FromComponents(Math.ScaleB(inverseRoot.High, inverseExponent),
|
||||
Math.ScaleB(inverseRoot.Low, inverseExponent));
|
||||
}
|
||||
|
||||
// For finite, nonzero normalized significands and exponents bounded by the
|
||||
// integer-power domain (|exponent| < 2^42). Keep the exponent separate until
|
||||
// the final result so an intermediate cannot overflow before reciprocation.
|
||||
|
||||
Reference in New Issue
Block a user