159 lines
5.8 KiB
C#
159 lines
5.8 KiB
C#
namespace Just.PreciseMath;
|
|
|
|
public readonly partial struct DoubleDouble
|
|
{
|
|
/// <summary>Gets the binary radix of the components.</summary>
|
|
public static int Radix => 2;
|
|
|
|
/// <summary>Returns the reciprocal with double-double precision.</summary>
|
|
/// <remarks>
|
|
/// Specializes scalar/DD division for a numerator of one, omitting only its
|
|
/// redundant numerator checks. The arithmetic sequence and boundary handling
|
|
/// are unchanged, preserving the high and low component bits of <c>1.0 / value</c>.
|
|
/// Results are approximate, not guaranteed correctly rounded;
|
|
/// finite results are tested against a relative error bound of 2^-100 plus one
|
|
/// minimum binary64 subnormal. Precision decreases near underflow.
|
|
/// Signed zeros map to signed infinities, signed infinities to signed zeros,
|
|
/// and NaN to canonical NaN. Finite overflow produces signed infinity.
|
|
/// </remarks>
|
|
[Pure]
|
|
public static DoubleDouble Reciprocal(DoubleDouble value)
|
|
{
|
|
const double one = 1.0;
|
|
if (!DoubleDouble.IsFinite(value) || value._high == 0.0)
|
|
{
|
|
return new DoubleDouble(one / value._high);
|
|
}
|
|
if (!PreciseMathHelper.IsDivisionWithinFastRange(value._high))
|
|
{
|
|
return PreciseMathHelper.DivideBoundary(one, value);
|
|
}
|
|
|
|
return PreciseMathHelper.DivideScalarFinite(one, value);
|
|
}
|
|
|
|
/// <summary>Returns the absolute value, preserving both components and canonicalizing NaN.</summary>
|
|
public static DoubleDouble Abs(DoubleDouble value)
|
|
{
|
|
if (IsNaN(value))
|
|
{
|
|
return NaN;
|
|
}
|
|
return IsNegative(value) ? -value : value;
|
|
}
|
|
|
|
/// <summary>Returns the operand with greater magnitude; ties prefer positive values and NaN propagates.</summary>
|
|
public static DoubleDouble MaxMagnitude(DoubleDouble x, DoubleDouble y)
|
|
{
|
|
if (IsNaN(x) || IsNaN(y))
|
|
{
|
|
return NaN;
|
|
}
|
|
DoubleDouble ax = Abs(x);
|
|
DoubleDouble ay = Abs(y);
|
|
return ax > ay || (ax == ay && !IsNegative(x)) ? x : y;
|
|
}
|
|
|
|
/// <summary>Returns the operand with lesser magnitude; ties prefer negative values and NaN propagates.</summary>
|
|
public static DoubleDouble MinMagnitude(DoubleDouble x, DoubleDouble y)
|
|
{
|
|
if (IsNaN(x) || IsNaN(y))
|
|
{
|
|
return NaN;
|
|
}
|
|
DoubleDouble ax = Abs(x);
|
|
DoubleDouble ay = Abs(y);
|
|
return ax < ay || (ax == ay && IsNegative(x)) ? x : y;
|
|
}
|
|
|
|
/// <summary>Returns the greater-magnitude operand, preferring a number over NaN and positive values on ties.</summary>
|
|
public static DoubleDouble MaxMagnitudeNumber(DoubleDouble x, DoubleDouble y)
|
|
{
|
|
if (IsNaN(x))
|
|
{
|
|
return y;
|
|
}
|
|
return IsNaN(y) ? x : MaxMagnitude(x, y);
|
|
}
|
|
|
|
/// <summary>Returns the lesser-magnitude operand, preferring a number over NaN and negative values on ties.</summary>
|
|
public static DoubleDouble MinMagnitudeNumber(DoubleDouble x, DoubleDouble y)
|
|
{
|
|
if (IsNaN(x))
|
|
{
|
|
return y;
|
|
}
|
|
return IsNaN(y) ? x : MinMagnitude(x, y);
|
|
}
|
|
|
|
/// <summary>Tests normalization and canonical NaN and zero-residual bit patterns.</summary>
|
|
public static bool IsCanonical(DoubleDouble value)
|
|
{
|
|
DoubleDouble normalized = FromComponents(value._high, value._low);
|
|
return BitConverter.DoubleToInt64Bits(value._high) == BitConverter.DoubleToInt64Bits(normalized._high)
|
|
&& BitConverter.DoubleToInt64Bits(value._low) == BitConverter.DoubleToInt64Bits(normalized._low);
|
|
}
|
|
|
|
/// <summary>Returns false: this type has no complex values.</summary>
|
|
public static bool IsComplexNumber(DoubleDouble value)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/// <summary>Returns false: this type has no imaginary values.</summary>
|
|
public static bool IsImaginaryNumber(DoubleDouble value)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/// <summary>Tests whether the value is real, including infinities but excluding NaN.</summary>
|
|
public static bool IsRealNumber(DoubleDouble value)
|
|
{
|
|
return !IsNaN(value);
|
|
}
|
|
|
|
/// <summary>Tests the high component's sign bit, including positive zero.</summary>
|
|
public static bool IsPositive(DoubleDouble value)
|
|
{
|
|
return double.IsPositive(value._high);
|
|
}
|
|
|
|
/// <summary>Tests whether the normalized high component is a normal binary64 value.</summary>
|
|
public static bool IsNormal(DoubleDouble value)
|
|
{
|
|
return double.IsNormal(value._high);
|
|
}
|
|
|
|
/// <summary>Tests whether the normalized high component is subnormal.</summary>
|
|
public static bool IsSubnormal(DoubleDouble value)
|
|
{
|
|
return double.IsSubnormal(value._high);
|
|
}
|
|
|
|
/// <summary>Tests for either sign of zero.</summary>
|
|
public static bool IsZero(DoubleDouble value)
|
|
{
|
|
return value._high == 0.0 && value._low == 0.0;
|
|
}
|
|
|
|
/// <summary>Tests whether the exact sum of the normalized components is an integer.</summary>
|
|
public static bool IsInteger(DoubleDouble value)
|
|
{
|
|
// In a normalized pair, a fractional high cannot be made integral by
|
|
// its nonoverlapping residual. An integral high requires an integral low.
|
|
return double.IsInteger(value._high) && double.IsInteger(value._low);
|
|
}
|
|
|
|
/// <summary>Tests integer parity without discarding the residual above 2^53.</summary>
|
|
public static bool IsEvenInteger(DoubleDouble value)
|
|
{
|
|
return IsInteger(value) && double.IsOddInteger(value._high) == double.IsOddInteger(value._low);
|
|
}
|
|
|
|
/// <summary>Tests integer parity without discarding the residual above 2^53.</summary>
|
|
public static bool IsOddInteger(DoubleDouble value)
|
|
{
|
|
return IsInteger(value) && double.IsOddInteger(value._high) != double.IsOddInteger(value._low);
|
|
}
|
|
}
|