Files
Just.PreciseMath/0-source/Just.PreciseMath/DoubleDouble.NumberBase.cs
T
just ac93744579
.NET Test / .NET tests (push) Successful in 2m11s
operators refactoring
2026-09-24 00:39:59 +04:00

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);
}
}