This commit is contained in:
+2
-2
@@ -117,8 +117,8 @@ csharp_style_expression_bodied_constructors = false:silent
|
||||
csharp_style_expression_bodied_indexers = true:silent
|
||||
csharp_style_expression_bodied_lambdas = true:suggestion
|
||||
csharp_style_expression_bodied_local_functions = false:silent
|
||||
csharp_style_expression_bodied_methods = false:silent
|
||||
csharp_style_expression_bodied_operators = false:silent
|
||||
csharp_style_expression_bodied_methods = when_on_single_line:silent
|
||||
csharp_style_expression_bodied_operators = when_on_single_line:silent
|
||||
csharp_style_expression_bodied_properties = true:silent
|
||||
|
||||
# Pattern matching preferences
|
||||
|
||||
@@ -44,18 +44,13 @@ public readonly partial struct DoubleDouble :
|
||||
}
|
||||
|
||||
/// <summary>Returns the operand unchanged.</summary>
|
||||
public static DoubleDouble Plus(DoubleDouble value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
public static DoubleDouble Plus(DoubleDouble value) => value;
|
||||
|
||||
/// <summary>Negates the value, including the high zero's sign, retaining canonical NaN and zero residuals.</summary>
|
||||
public static DoubleDouble Negate(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,
|
||||
new DoubleDouble(double.IsNaN(value._high) ? double.NaN : -value._high,
|
||||
value._low == 0.0 ? 0.0 : -value._low);
|
||||
}
|
||||
|
||||
/// <summary>Adds normalized expansions, retaining low-sum residuals under cancellation.</summary>
|
||||
public static DoubleDouble Add(DoubleDouble left, DoubleDouble right)
|
||||
@@ -159,32 +154,21 @@ 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 Add(DoubleDouble left, double right)
|
||||
{
|
||||
return PreciseMathHelper.AddScalar(left._high, left._low, right);
|
||||
}
|
||||
public static DoubleDouble Add(DoubleDouble left, double right) => 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 Add(double left, DoubleDouble right)
|
||||
{
|
||||
return Add(right, left);
|
||||
}
|
||||
public static DoubleDouble Add(double left, DoubleDouble right) => 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 Subtract(DoubleDouble left, double right)
|
||||
{
|
||||
return PreciseMathHelper.AddScalar(left._high, left._low, -right);
|
||||
}
|
||||
public static DoubleDouble Subtract(DoubleDouble left, double right) => 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 Subtract(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);
|
||||
}
|
||||
PreciseMathHelper.AddScalar(-right._high, -right._low, left);
|
||||
|
||||
/// <summary>Applies the expansion operation without discarding the low component.</summary>
|
||||
public static DoubleDouble Multiply(DoubleDouble left, double right)
|
||||
@@ -207,10 +191,7 @@ public readonly partial struct DoubleDouble :
|
||||
}
|
||||
|
||||
/// <summary>Applies the expansion operation without discarding the low component.</summary>
|
||||
public static DoubleDouble Multiply(double left, DoubleDouble right)
|
||||
{
|
||||
return Multiply(right, left);
|
||||
}
|
||||
public static DoubleDouble Multiply(double left, DoubleDouble right) => 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>
|
||||
|
||||
@@ -8,27 +8,18 @@ public readonly partial struct DoubleDouble :
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
[Pure]
|
||||
public bool Equals(DoubleDouble other)
|
||||
{
|
||||
return _high.Equals(other._high) && _low.Equals(other._low);
|
||||
}
|
||||
public bool Equals(DoubleDouble other) => _high.Equals(other._high) && _low.Equals(other._low);
|
||||
|
||||
/// <summary>
|
||||
/// Tests numerical equality; NaN operands are never equal.
|
||||
/// </summary>
|
||||
[Pure, MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(DoubleDouble left, DoubleDouble right)
|
||||
{
|
||||
return left._high == right._high && left._low == right._low;
|
||||
}
|
||||
public static bool operator ==(DoubleDouble left, DoubleDouble right) => left._high == right._high && left._low == right._low;
|
||||
/// <summary>
|
||||
/// Tests numerical inequality; NaN operands are always unequal.
|
||||
/// </summary>
|
||||
[Pure, MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(DoubleDouble left, DoubleDouble right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
public static bool operator !=(DoubleDouble left, DoubleDouble right) => !(left == right);
|
||||
|
||||
/// <summary>Orders NaN before other values, and compares finite values using both components.</summary>
|
||||
public int CompareTo(DoubleDouble other)
|
||||
@@ -51,63 +42,33 @@ public readonly partial struct DoubleDouble :
|
||||
throw new ArgumentException($"Object must be of type {nameof(DoubleDouble)}.", nameof(obj));
|
||||
}
|
||||
|
||||
/// <summary>Compares both components; NaN operands are unordered.</summary>
|
||||
public static bool operator <(DoubleDouble left, DoubleDouble right) => left._high < right._high || (left._high == right._high && left._low < right._low);
|
||||
|
||||
/// <summary>Compares both components; NaN operands are unordered.</summary>
|
||||
public static bool operator >(DoubleDouble left, DoubleDouble right) => left._high > right._high || (left._high == right._high && left._low > right._low);
|
||||
|
||||
/// <summary>Compares both components; NaN operands are unordered.</summary>
|
||||
public static bool operator <=(DoubleDouble left, DoubleDouble right) => left._high < right._high || (left._high == right._high && left._low <= right._low);
|
||||
|
||||
/// <summary>Compares both components; NaN operands are unordered.</summary>
|
||||
public static bool operator >=(DoubleDouble left, DoubleDouble right) => left._high > right._high || (left._high == right._high && left._low >= right._low);
|
||||
|
||||
/// <summary>Applies binary64 IsNaN classification to the canonical high component.</summary>
|
||||
public static bool IsNaN(DoubleDouble value)
|
||||
{
|
||||
return double.IsNaN(value._high);
|
||||
}
|
||||
public static bool IsNaN(DoubleDouble value) => double.IsNaN(value._high);
|
||||
|
||||
/// <summary>Applies binary64 IsFinite classification to the canonical high component.</summary>
|
||||
public static bool IsFinite(DoubleDouble value)
|
||||
{
|
||||
return double.IsFinite(value._high);
|
||||
}
|
||||
public static bool IsFinite(DoubleDouble value) => double.IsFinite(value._high);
|
||||
|
||||
/// <summary>Applies binary64 IsInfinity classification to the canonical high component.</summary>
|
||||
public static bool IsInfinity(DoubleDouble value)
|
||||
{
|
||||
return double.IsInfinity(value._high);
|
||||
}
|
||||
public static bool IsInfinity(DoubleDouble value) => double.IsInfinity(value._high);
|
||||
|
||||
/// <summary>Applies binary64 IsPositiveInfinity classification to the canonical high component.</summary>
|
||||
public static bool IsPositiveInfinity(DoubleDouble value)
|
||||
{
|
||||
return double.IsPositiveInfinity(value._high);
|
||||
}
|
||||
public static bool IsPositiveInfinity(DoubleDouble value) => double.IsPositiveInfinity(value._high);
|
||||
|
||||
/// <summary>Applies binary64 IsNegativeInfinity classification to the canonical high component.</summary>
|
||||
public static bool IsNegativeInfinity(DoubleDouble value)
|
||||
{
|
||||
return double.IsNegativeInfinity(value._high);
|
||||
}
|
||||
public static bool IsNegativeInfinity(DoubleDouble value) => double.IsNegativeInfinity(value._high);
|
||||
|
||||
/// <summary>Applies binary64 IsNegative classification to the canonical high component.</summary>
|
||||
public static bool IsNegative(DoubleDouble value)
|
||||
{
|
||||
return double.IsNegative(value._high);
|
||||
}
|
||||
|
||||
/// <summary>Compares both components; NaN operands are unordered.</summary>
|
||||
public static bool operator <(DoubleDouble left, DoubleDouble right)
|
||||
{
|
||||
return left._high < right._high || (left._high == right._high && left._low < right._low);
|
||||
}
|
||||
|
||||
/// <summary>Compares both components; NaN operands are unordered.</summary>
|
||||
public static bool operator >(DoubleDouble left, DoubleDouble right)
|
||||
{
|
||||
return left._high > right._high || (left._high == right._high && left._low > right._low);
|
||||
}
|
||||
|
||||
/// <summary>Compares both components; NaN operands are unordered.</summary>
|
||||
public static bool operator <=(DoubleDouble left, DoubleDouble right)
|
||||
{
|
||||
return left._high < right._high || (left._high == right._high && left._low <= right._low);
|
||||
}
|
||||
|
||||
/// <summary>Compares both components; NaN operands are unordered.</summary>
|
||||
public static bool operator >=(DoubleDouble left, DoubleDouble right)
|
||||
{
|
||||
return left._high > right._high || (left._high == right._high && left._low >= right._low);
|
||||
}
|
||||
public static bool IsNegative(DoubleDouble value) => double.IsNegative(value._high);
|
||||
}
|
||||
|
||||
@@ -9,80 +9,35 @@ namespace Just.PreciseMath;
|
||||
/// </remarks>
|
||||
public readonly partial struct DoubleDouble : IConvertible
|
||||
{
|
||||
TypeCode IConvertible.GetTypeCode()
|
||||
{
|
||||
return TypeCode.Object;
|
||||
}
|
||||
TypeCode IConvertible.GetTypeCode() => TypeCode.Object;
|
||||
|
||||
bool IConvertible.ToBoolean(IFormatProvider? provider)
|
||||
{
|
||||
return _high != 0.0;
|
||||
}
|
||||
bool IConvertible.ToBoolean(IFormatProvider? provider) => _high != 0.0;
|
||||
|
||||
char IConvertible.ToChar(IFormatProvider? provider)
|
||||
{
|
||||
throw new InvalidCastException("DoubleDouble cannot be converted to Char.");
|
||||
}
|
||||
char IConvertible.ToChar(IFormatProvider? provider) => throw new InvalidCastException("DoubleDouble cannot be converted to Char.");
|
||||
|
||||
DateTime IConvertible.ToDateTime(IFormatProvider? provider)
|
||||
{
|
||||
throw new InvalidCastException("DoubleDouble cannot be converted to DateTime.");
|
||||
}
|
||||
DateTime IConvertible.ToDateTime(IFormatProvider? provider) => throw new InvalidCastException("DoubleDouble cannot be converted to DateTime.");
|
||||
|
||||
byte IConvertible.ToByte(IFormatProvider? provider)
|
||||
{
|
||||
return (byte)ConversionRoundedInteger();
|
||||
}
|
||||
byte IConvertible.ToByte(IFormatProvider? provider) => (byte)ConversionRoundedInteger();
|
||||
|
||||
sbyte IConvertible.ToSByte(IFormatProvider? provider)
|
||||
{
|
||||
return (sbyte)ConversionRoundedInteger();
|
||||
}
|
||||
sbyte IConvertible.ToSByte(IFormatProvider? provider) => (sbyte)ConversionRoundedInteger();
|
||||
|
||||
short IConvertible.ToInt16(IFormatProvider? provider)
|
||||
{
|
||||
return (short)ConversionRoundedInteger();
|
||||
}
|
||||
short IConvertible.ToInt16(IFormatProvider? provider) => (short)ConversionRoundedInteger();
|
||||
|
||||
ushort IConvertible.ToUInt16(IFormatProvider? provider)
|
||||
{
|
||||
return (ushort)ConversionRoundedInteger();
|
||||
}
|
||||
ushort IConvertible.ToUInt16(IFormatProvider? provider) => (ushort)ConversionRoundedInteger();
|
||||
|
||||
int IConvertible.ToInt32(IFormatProvider? provider)
|
||||
{
|
||||
return (int)ConversionRoundedInteger();
|
||||
}
|
||||
int IConvertible.ToInt32(IFormatProvider? provider) => (int)ConversionRoundedInteger();
|
||||
|
||||
uint IConvertible.ToUInt32(IFormatProvider? provider)
|
||||
{
|
||||
return (uint)ConversionRoundedInteger();
|
||||
}
|
||||
uint IConvertible.ToUInt32(IFormatProvider? provider) => (uint)ConversionRoundedInteger();
|
||||
|
||||
long IConvertible.ToInt64(IFormatProvider? provider)
|
||||
{
|
||||
return (long)ConversionRoundedInteger();
|
||||
}
|
||||
long IConvertible.ToInt64(IFormatProvider? provider) => (long)ConversionRoundedInteger();
|
||||
|
||||
ulong IConvertible.ToUInt64(IFormatProvider? provider)
|
||||
{
|
||||
return (ulong)ConversionRoundedInteger();
|
||||
}
|
||||
ulong IConvertible.ToUInt64(IFormatProvider? provider) => (ulong)ConversionRoundedInteger();
|
||||
|
||||
decimal IConvertible.ToDecimal(IFormatProvider? provider)
|
||||
{
|
||||
return (decimal)this;
|
||||
}
|
||||
decimal IConvertible.ToDecimal(IFormatProvider? provider) => (decimal)this;
|
||||
|
||||
double IConvertible.ToDouble(IFormatProvider? provider)
|
||||
{
|
||||
return (double)this;
|
||||
}
|
||||
double IConvertible.ToDouble(IFormatProvider? provider) => (double)this;
|
||||
|
||||
float IConvertible.ToSingle(IFormatProvider? provider)
|
||||
{
|
||||
return (float)this;
|
||||
}
|
||||
float IConvertible.ToSingle(IFormatProvider? provider) => (float)this;
|
||||
|
||||
object IConvertible.ToType(Type conversionType, IFormatProvider? provider)
|
||||
{
|
||||
|
||||
@@ -5,22 +5,13 @@ namespace Just.PreciseMath;
|
||||
public readonly partial struct DoubleDouble : IFormattable
|
||||
{
|
||||
/// <summary>Formats with G32 and the current culture.</summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return ToString(null, null);
|
||||
}
|
||||
public override string ToString() => ToString(null, null);
|
||||
|
||||
/// <summary>Formats with the specified G, E, or F format and the current culture.</summary>
|
||||
public string ToString(string? format)
|
||||
{
|
||||
return ToString(format, null);
|
||||
}
|
||||
public string ToString(string? format) => ToString(format, null);
|
||||
|
||||
/// <summary>Formats with G32 and the supplied culture (or current culture when null).</summary>
|
||||
public string ToString(IFormatProvider? provider)
|
||||
{
|
||||
return ToString(null, provider);
|
||||
}
|
||||
public string ToString(IFormatProvider? provider) => ToString(null, provider);
|
||||
|
||||
/// <summary>Returns the exact decimal expansion of the stored value using invariant culture.</summary>
|
||||
/// <remarks>
|
||||
|
||||
@@ -45,35 +45,17 @@ public readonly partial struct DoubleDouble
|
||||
throw new NotSupportedException($"Conversion from {typeof(TOther)} to DoubleDouble is not supported.");
|
||||
}
|
||||
|
||||
static bool INumberBase<DoubleDouble>.TryConvertFromChecked<TOther>(TOther value, out DoubleDouble result)
|
||||
{
|
||||
return GenericTryConvertFrom(value, out result);
|
||||
}
|
||||
static bool INumberBase<DoubleDouble>.TryConvertFromChecked<TOther>(TOther value, out DoubleDouble result) => GenericTryConvertFrom(value, out result);
|
||||
|
||||
static bool INumberBase<DoubleDouble>.TryConvertFromSaturating<TOther>(TOther value, out DoubleDouble result)
|
||||
{
|
||||
return GenericTryConvertFrom(value, out result);
|
||||
}
|
||||
static bool INumberBase<DoubleDouble>.TryConvertFromSaturating<TOther>(TOther value, out DoubleDouble result) => GenericTryConvertFrom(value, out result);
|
||||
|
||||
static bool INumberBase<DoubleDouble>.TryConvertFromTruncating<TOther>(TOther value, out DoubleDouble result)
|
||||
{
|
||||
return GenericTryConvertFrom(value, out result);
|
||||
}
|
||||
static bool INumberBase<DoubleDouble>.TryConvertFromTruncating<TOther>(TOther value, out DoubleDouble result) => GenericTryConvertFrom(value, out result);
|
||||
|
||||
static bool INumberBase<DoubleDouble>.TryConvertToChecked<TOther>(DoubleDouble value, out TOther result)
|
||||
{
|
||||
return GenericTryConvertTo(value, GenericConversionMode.Checked, out result);
|
||||
}
|
||||
static bool INumberBase<DoubleDouble>.TryConvertToChecked<TOther>(DoubleDouble value, out TOther result) => GenericTryConvertTo(value, GenericConversionMode.Checked, out result);
|
||||
|
||||
static bool INumberBase<DoubleDouble>.TryConvertToSaturating<TOther>(DoubleDouble value, out TOther result)
|
||||
{
|
||||
return GenericTryConvertTo(value, GenericConversionMode.Saturating, out result);
|
||||
}
|
||||
static bool INumberBase<DoubleDouble>.TryConvertToSaturating<TOther>(DoubleDouble value, out TOther result) => GenericTryConvertTo(value, GenericConversionMode.Saturating, out result);
|
||||
|
||||
static bool INumberBase<DoubleDouble>.TryConvertToTruncating<TOther>(DoubleDouble value, out TOther result)
|
||||
{
|
||||
return GenericTryConvertTo(value, GenericConversionMode.Truncating, out result);
|
||||
}
|
||||
static bool INumberBase<DoubleDouble>.TryConvertToTruncating<TOther>(DoubleDouble value, out TOther result) => GenericTryConvertTo(value, GenericConversionMode.Truncating, out result);
|
||||
|
||||
private enum GenericConversionMode
|
||||
{
|
||||
@@ -82,16 +64,13 @@ public readonly partial struct DoubleDouble
|
||||
Truncating,
|
||||
}
|
||||
|
||||
private static bool GenericIsInteger<TOther>()
|
||||
{
|
||||
return typeof(TOther) == typeof(byte) || typeof(TOther) == typeof(sbyte)
|
||||
private static bool GenericIsInteger<TOther>() => typeof(TOther) == typeof(byte) || typeof(TOther) == typeof(sbyte)
|
||||
|| typeof(TOther) == typeof(short) || typeof(TOther) == typeof(ushort)
|
||||
|| typeof(TOther) == typeof(int) || typeof(TOther) == typeof(uint)
|
||||
|| typeof(TOther) == typeof(long) || typeof(TOther) == typeof(ulong)
|
||||
|| typeof(TOther) == typeof(nint) || typeof(TOther) == typeof(nuint)
|
||||
|| typeof(TOther) == typeof(Int128) || typeof(TOther) == typeof(UInt128)
|
||||
|| typeof(TOther) == typeof(char) || typeof(TOther) == typeof(BigInteger);
|
||||
}
|
||||
|
||||
private static bool GenericTryConvertFrom<TOther>(TOther value, out DoubleDouble result) where TOther : INumberBase<TOther>
|
||||
{
|
||||
|
||||
@@ -95,64 +95,35 @@ public readonly partial struct DoubleDouble
|
||||
}
|
||||
|
||||
/// <summary>Returns false: this type has no complex values.</summary>
|
||||
public static bool IsComplexNumber(DoubleDouble value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
public static bool IsComplexNumber(DoubleDouble value) => false;
|
||||
|
||||
/// <summary>Returns false: this type has no imaginary values.</summary>
|
||||
public static bool IsImaginaryNumber(DoubleDouble value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
public static bool IsImaginaryNumber(DoubleDouble value) => false;
|
||||
|
||||
/// <summary>Tests whether the value is real, including infinities but excluding NaN.</summary>
|
||||
public static bool IsRealNumber(DoubleDouble value)
|
||||
{
|
||||
return !IsNaN(value);
|
||||
}
|
||||
public static bool IsRealNumber(DoubleDouble value) => !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);
|
||||
}
|
||||
public static bool IsPositive(DoubleDouble value) => 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);
|
||||
}
|
||||
public static bool IsNormal(DoubleDouble value) => 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);
|
||||
}
|
||||
public static bool IsSubnormal(DoubleDouble value) => 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;
|
||||
}
|
||||
public static bool IsZero(DoubleDouble value) => 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
public static bool IsEvenInteger(DoubleDouble value) => 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);
|
||||
}
|
||||
public static bool IsOddInteger(DoubleDouble value) => IsInteger(value) && double.IsOddInteger(value._high) != double.IsOddInteger(value._low);
|
||||
}
|
||||
|
||||
@@ -33,10 +33,7 @@ public readonly partial struct DoubleDouble
|
||||
|
||||
/// <summary>Parses decimal text; returns false and Zero for null, invalid, or oversized input.</summary>
|
||||
/// <exception cref="ArgumentException">The style contains hexadecimal, binary, or undefined flags.</exception>
|
||||
public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out DoubleDouble result)
|
||||
{
|
||||
return TryParse(s.AsSpan(), style, provider, out result);
|
||||
}
|
||||
public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out DoubleDouble result) => TryParse(s.AsSpan(), style, provider, out result);
|
||||
|
||||
/// <summary>Parses decimal text; returns false and Zero for invalid or oversized input.</summary>
|
||||
/// <remarks>Group sizes are not validated. Currency styles recognize currency separators, and number
|
||||
|
||||
@@ -3,98 +3,50 @@ namespace Just.PreciseMath;
|
||||
public readonly partial struct DoubleDouble
|
||||
{
|
||||
/// <inheritdoc cref="Plus"/>
|
||||
public static DoubleDouble operator +(DoubleDouble value)
|
||||
{
|
||||
return Plus(value);
|
||||
}
|
||||
public static DoubleDouble operator +(DoubleDouble value) => Plus(value);
|
||||
|
||||
/// <inheritdoc cref="Negate"/>
|
||||
public static DoubleDouble operator -(DoubleDouble value)
|
||||
{
|
||||
return Negate(value);
|
||||
}
|
||||
public static DoubleDouble operator -(DoubleDouble value) => Negate(value);
|
||||
|
||||
/// <inheritdoc cref="Add(DoubleDouble, DoubleDouble)"/>
|
||||
public static DoubleDouble operator +(DoubleDouble left, DoubleDouble right)
|
||||
{
|
||||
return Add(left, right);
|
||||
}
|
||||
public static DoubleDouble operator +(DoubleDouble left, DoubleDouble right) => Add(left, right);
|
||||
|
||||
/// <inheritdoc cref="Subtract(DoubleDouble, DoubleDouble)"/>
|
||||
public static DoubleDouble operator -(DoubleDouble left, DoubleDouble right)
|
||||
{
|
||||
return Subtract(left, right);
|
||||
}
|
||||
public static DoubleDouble operator -(DoubleDouble left, DoubleDouble right) => Subtract(left, right);
|
||||
|
||||
/// <inheritdoc cref="Multiply(DoubleDouble, DoubleDouble)"/>
|
||||
public static DoubleDouble operator *(DoubleDouble left, DoubleDouble right)
|
||||
{
|
||||
return Multiply(left, right);
|
||||
}
|
||||
public static DoubleDouble operator *(DoubleDouble left, DoubleDouble right) => Multiply(left, right);
|
||||
|
||||
/// <inheritdoc cref="Divide(DoubleDouble, DoubleDouble)"/>
|
||||
public static DoubleDouble operator /(DoubleDouble left, DoubleDouble right)
|
||||
{
|
||||
return Divide(left, right);
|
||||
}
|
||||
public static DoubleDouble operator /(DoubleDouble left, DoubleDouble right) => Divide(left, right);
|
||||
|
||||
/// <inheritdoc cref="Add(DoubleDouble, double)"/>
|
||||
public static DoubleDouble operator +(DoubleDouble left, double right)
|
||||
{
|
||||
return Add(left, right);
|
||||
}
|
||||
public static DoubleDouble operator +(DoubleDouble left, double right) => Add(left, right);
|
||||
|
||||
/// <inheritdoc cref="Add(double, DoubleDouble)"/>
|
||||
public static DoubleDouble operator +(double left, DoubleDouble right)
|
||||
{
|
||||
return Add(left, right);
|
||||
}
|
||||
public static DoubleDouble operator +(double left, DoubleDouble right) => Add(left, right);
|
||||
|
||||
/// <inheritdoc cref="Subtract(DoubleDouble, double)"/>
|
||||
public static DoubleDouble operator -(DoubleDouble left, double right)
|
||||
{
|
||||
return Subtract(left, right);
|
||||
}
|
||||
public static DoubleDouble operator -(DoubleDouble left, double right) => Subtract(left, right);
|
||||
|
||||
/// <inheritdoc cref="Subtract(double, DoubleDouble)"/>
|
||||
public static DoubleDouble operator -(double left, DoubleDouble right)
|
||||
{
|
||||
return Subtract(left, right);
|
||||
}
|
||||
public static DoubleDouble operator -(double left, DoubleDouble right) => Subtract(left, right);
|
||||
|
||||
/// <inheritdoc cref="Multiply(DoubleDouble, double)"/>
|
||||
public static DoubleDouble operator *(DoubleDouble left, double right)
|
||||
{
|
||||
return Multiply(left, right);
|
||||
}
|
||||
public static DoubleDouble operator *(DoubleDouble left, double right) => Multiply(left, right);
|
||||
|
||||
/// <inheritdoc cref="Multiply(double, DoubleDouble)"/>
|
||||
public static DoubleDouble operator *(double left, DoubleDouble right)
|
||||
{
|
||||
return Multiply(left, right);
|
||||
}
|
||||
public static DoubleDouble operator *(double left, DoubleDouble right) => Multiply(left, right);
|
||||
|
||||
/// <inheritdoc cref="Divide(DoubleDouble, double)"/>
|
||||
public static DoubleDouble operator /(DoubleDouble left, double right)
|
||||
{
|
||||
return Divide(left, right);
|
||||
}
|
||||
public static DoubleDouble operator /(DoubleDouble left, double right) => Divide(left, right);
|
||||
|
||||
/// <inheritdoc cref="Divide(double, DoubleDouble)"/>
|
||||
public static DoubleDouble operator /(double left, DoubleDouble right)
|
||||
{
|
||||
return Divide(left, right);
|
||||
}
|
||||
public static DoubleDouble operator /(double left, DoubleDouble right) => 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);
|
||||
}
|
||||
public static DoubleDouble operator ++(DoubleDouble value) => 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);
|
||||
}
|
||||
public static DoubleDouble operator --(DoubleDouble value) => Subtract(value, 1.0);
|
||||
}
|
||||
|
||||
@@ -41,22 +41,13 @@ public readonly partial struct DoubleDouble : ISpanParsable<DoubleDouble>
|
||||
}
|
||||
|
||||
/// <summary>Parses using the current culture. Returns false and Zero for null, invalid, or oversized input.</summary>
|
||||
public static bool TryParse(string? s, out DoubleDouble result)
|
||||
{
|
||||
return TryParse(s, null, out result);
|
||||
}
|
||||
public static bool TryParse(string? s, out DoubleDouble result) => TryParse(s, null, out result);
|
||||
|
||||
/// <summary>Parses using the supplied culture (current when null). Returns false and Zero for null, invalid, or oversized input.</summary>
|
||||
public static bool TryParse(string? s, IFormatProvider? provider, out DoubleDouble result)
|
||||
{
|
||||
return TryParse(s.AsSpan(), provider, out result);
|
||||
}
|
||||
public static bool TryParse(string? s, IFormatProvider? provider, out DoubleDouble result) => TryParse(s.AsSpan(), provider, out result);
|
||||
|
||||
/// <summary>Parses using the current culture. Returns false and Zero for invalid or oversized input.</summary>
|
||||
public static bool TryParse(ReadOnlySpan<char> s, out DoubleDouble result)
|
||||
{
|
||||
return TryParse(s, null, out result);
|
||||
}
|
||||
public static bool TryParse(ReadOnlySpan<char> s, out DoubleDouble result) => TryParse(s, null, out result);
|
||||
|
||||
/// <summary>Parses using the supplied culture (current when null). Returns false and Zero for invalid or oversized input.</summary>
|
||||
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, out DoubleDouble result)
|
||||
|
||||
@@ -80,10 +80,7 @@ public readonly partial struct DoubleDouble
|
||||
/// The base retains both components.
|
||||
/// </remarks>
|
||||
[Pure]
|
||||
public static DoubleDouble Pow(DoubleDouble value, double exponent)
|
||||
{
|
||||
return Pow(value, new DoubleDouble(exponent));
|
||||
}
|
||||
public static DoubleDouble Pow(DoubleDouble value, double exponent) => Pow(value, new DoubleDouble(exponent));
|
||||
|
||||
/// <summary>Raises a double-double value to a double-double power.</summary>
|
||||
/// <remarks>
|
||||
|
||||
@@ -83,16 +83,10 @@ public readonly partial struct DoubleDouble :
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Pure]
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is DoubleDouble other && Equals(other);
|
||||
}
|
||||
public override bool Equals(object? obj) => obj is DoubleDouble other && Equals(other);
|
||||
/// <inheritdoc/>
|
||||
[Pure]
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(_high, _low);
|
||||
}
|
||||
public override int GetHashCode() => HashCode.Combine(_high, _low);
|
||||
|
||||
/// <summary>Returns the normalized components.</summary>
|
||||
public void Decompose(out double high, out double low)
|
||||
|
||||
@@ -9,120 +9,69 @@ public static class DoubleDoubleExtensions
|
||||
{
|
||||
/// <inheritdoc cref="DoubleDouble.Abs(DoubleDouble)"/>
|
||||
[Pure]
|
||||
public static DoubleDouble Abs(this DoubleDouble value)
|
||||
{
|
||||
return DoubleDouble.Abs(value);
|
||||
}
|
||||
public static DoubleDouble Abs(this DoubleDouble value) => DoubleDouble.Abs(value);
|
||||
|
||||
/// <inheritdoc cref="DoubleDouble.Square(DoubleDouble)"/>
|
||||
[Pure]
|
||||
public static DoubleDouble Square(this DoubleDouble value)
|
||||
{
|
||||
return DoubleDouble.Square(value);
|
||||
}
|
||||
public static DoubleDouble Square(this DoubleDouble value) => DoubleDouble.Square(value);
|
||||
|
||||
/// <inheritdoc cref="DoubleDouble.Reciprocal(DoubleDouble)"/>
|
||||
[Pure]
|
||||
public static DoubleDouble Reciprocal(this DoubleDouble value)
|
||||
{
|
||||
return DoubleDouble.Reciprocal(value);
|
||||
}
|
||||
public static DoubleDouble Reciprocal(this DoubleDouble value) => DoubleDouble.Reciprocal(value);
|
||||
|
||||
/// <inheritdoc cref="DoubleDouble.Sqrt(DoubleDouble)"/>
|
||||
[Pure]
|
||||
public static DoubleDouble Sqrt(this DoubleDouble value)
|
||||
{
|
||||
return DoubleDouble.Sqrt(value);
|
||||
}
|
||||
public static DoubleDouble Sqrt(this DoubleDouble value) => DoubleDouble.Sqrt(value);
|
||||
|
||||
/// <inheritdoc cref="DoubleDouble.InvSqrt(DoubleDouble)"/>
|
||||
[Pure]
|
||||
public static DoubleDouble InvSqrt(this DoubleDouble value)
|
||||
{
|
||||
return DoubleDouble.InvSqrt(value);
|
||||
}
|
||||
public static DoubleDouble InvSqrt(this DoubleDouble value) => DoubleDouble.InvSqrt(value);
|
||||
|
||||
/// <inheritdoc cref="DoubleDouble.Cbrt(DoubleDouble)"/>
|
||||
[Pure]
|
||||
public static DoubleDouble Cbrt(this DoubleDouble value)
|
||||
{
|
||||
return DoubleDouble.Cbrt(value);
|
||||
}
|
||||
public static DoubleDouble Cbrt(this DoubleDouble value) => DoubleDouble.Cbrt(value);
|
||||
|
||||
/// <inheritdoc cref="DoubleDouble.Exp(DoubleDouble)"/>
|
||||
[Pure]
|
||||
public static DoubleDouble Exp(this DoubleDouble value)
|
||||
{
|
||||
return DoubleDouble.Exp(value);
|
||||
}
|
||||
public static DoubleDouble Exp(this DoubleDouble value) => DoubleDouble.Exp(value);
|
||||
|
||||
/// <inheritdoc cref="DoubleDouble.Exp2(DoubleDouble)"/>
|
||||
[Pure]
|
||||
public static DoubleDouble Exp2(this DoubleDouble value)
|
||||
{
|
||||
return DoubleDouble.Exp2(value);
|
||||
}
|
||||
public static DoubleDouble Exp2(this DoubleDouble value) => DoubleDouble.Exp2(value);
|
||||
|
||||
/// <inheritdoc cref="DoubleDouble.Exp10(DoubleDouble)"/>
|
||||
[Pure]
|
||||
public static DoubleDouble Exp10(this DoubleDouble value)
|
||||
{
|
||||
return DoubleDouble.Exp10(value);
|
||||
}
|
||||
public static DoubleDouble Exp10(this DoubleDouble value) => DoubleDouble.Exp10(value);
|
||||
|
||||
/// <inheritdoc cref="DoubleDouble.ExpM1(DoubleDouble)"/>
|
||||
[Pure]
|
||||
public static DoubleDouble ExpM1(this DoubleDouble value)
|
||||
{
|
||||
return DoubleDouble.ExpM1(value);
|
||||
}
|
||||
public static DoubleDouble ExpM1(this DoubleDouble value) => DoubleDouble.ExpM1(value);
|
||||
|
||||
/// <inheritdoc cref="DoubleDouble.Exp2M1(DoubleDouble)"/>
|
||||
[Pure]
|
||||
public static DoubleDouble Exp2M1(this DoubleDouble value)
|
||||
{
|
||||
return DoubleDouble.Exp2M1(value);
|
||||
}
|
||||
public static DoubleDouble Exp2M1(this DoubleDouble value) => DoubleDouble.Exp2M1(value);
|
||||
|
||||
/// <inheritdoc cref="DoubleDouble.Exp10M1(DoubleDouble)"/>
|
||||
[Pure]
|
||||
public static DoubleDouble Exp10M1(this DoubleDouble value)
|
||||
{
|
||||
return DoubleDouble.Exp10M1(value);
|
||||
}
|
||||
public static DoubleDouble Exp10M1(this DoubleDouble value) => DoubleDouble.Exp10M1(value);
|
||||
|
||||
/// <inheritdoc cref="DoubleDouble.Log(DoubleDouble)"/>
|
||||
[Pure]
|
||||
public static DoubleDouble Log(this DoubleDouble value)
|
||||
{
|
||||
return DoubleDouble.Log(value);
|
||||
}
|
||||
public static DoubleDouble Log(this DoubleDouble value) => DoubleDouble.Log(value);
|
||||
|
||||
/// <inheritdoc cref="DoubleDouble.RootN(DoubleDouble, int)"/>
|
||||
[Pure]
|
||||
public static DoubleDouble RootN(this DoubleDouble value, int n)
|
||||
{
|
||||
return DoubleDouble.RootN(value, n);
|
||||
}
|
||||
public static DoubleDouble RootN(this DoubleDouble value, int n) => 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);
|
||||
}
|
||||
public static DoubleDouble Pow(this DoubleDouble value, int exponent) => 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);
|
||||
}
|
||||
public static DoubleDouble Pow(this DoubleDouble value, double exponent) => 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);
|
||||
}
|
||||
public static DoubleDouble Pow(this DoubleDouble value, DoubleDouble exponent) => DoubleDouble.Pow(value, exponent);
|
||||
}
|
||||
|
||||
@@ -211,40 +211,22 @@ internal static class PreciseMathHelper
|
||||
// All inputs must be finite and normalized; division denominators must be nonzero.
|
||||
// Callers retain the special-value, signed-zero, and exponent-range dispatch.
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
internal static DoubleDouble AddBoundary(DoubleDouble left, DoubleDouble right)
|
||||
{
|
||||
return ArithmeticFromRatio(ArithmeticUnits(left) + ArithmeticUnits(right), BigInteger.One << 1074);
|
||||
}
|
||||
internal static DoubleDouble AddBoundary(DoubleDouble left, DoubleDouble right) => ArithmeticFromRatio(ArithmeticUnits(left) + ArithmeticUnits(right), BigInteger.One << 1074);
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
internal static DoubleDouble MultiplyBoundary(DoubleDouble left, DoubleDouble right)
|
||||
{
|
||||
return ArithmeticFromRatio(ArithmeticUnits(left) * ArithmeticUnits(right), BigInteger.One << 2148);
|
||||
}
|
||||
internal static DoubleDouble MultiplyBoundary(DoubleDouble left, DoubleDouble right) => ArithmeticFromRatio(ArithmeticUnits(left) * ArithmeticUnits(right), BigInteger.One << 2148);
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
internal static DoubleDouble MultiplyBoundary(DoubleDouble left, double right)
|
||||
{
|
||||
return ArithmeticFromRatio(ArithmeticUnits(left) * ArithmeticUnits(right), BigInteger.One << 2148);
|
||||
}
|
||||
internal static DoubleDouble MultiplyBoundary(DoubleDouble left, double right) => ArithmeticFromRatio(ArithmeticUnits(left) * ArithmeticUnits(right), BigInteger.One << 2148);
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
internal static DoubleDouble DivideBoundary(DoubleDouble left, DoubleDouble right)
|
||||
{
|
||||
return ArithmeticFromRatio(ArithmeticUnits(left), ArithmeticUnits(right));
|
||||
}
|
||||
internal static DoubleDouble DivideBoundary(DoubleDouble left, DoubleDouble right) => ArithmeticFromRatio(ArithmeticUnits(left), ArithmeticUnits(right));
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
internal static DoubleDouble DivideBoundary(DoubleDouble left, double right)
|
||||
{
|
||||
return ArithmeticFromRatio(ArithmeticUnits(left), ArithmeticUnits(right));
|
||||
}
|
||||
internal static DoubleDouble DivideBoundary(DoubleDouble left, double right) => ArithmeticFromRatio(ArithmeticUnits(left), ArithmeticUnits(right));
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
internal static DoubleDouble DivideBoundary(double left, DoubleDouble right)
|
||||
{
|
||||
return ArithmeticFromRatio(ArithmeticUnits(left), ArithmeticUnits(right));
|
||||
}
|
||||
internal static DoubleDouble DivideBoundary(double left, DoubleDouble right) => ArithmeticFromRatio(ArithmeticUnits(left), ArithmeticUnits(right));
|
||||
|
||||
// For finite, nonzero normalized significands and exponents bounded by the
|
||||
// integer-power domain (|exponent| < 2^42). Keep the exponent separate until
|
||||
@@ -297,10 +279,7 @@ internal static class PreciseMathHelper
|
||||
// The boundary path uses bounded binary integers (at most about 4200 bits), not
|
||||
// arbitrary-precision storage. It avoids overflow and double rounding in EFTs
|
||||
// at the binary64 exponent limits. The common path remains allocation-free.
|
||||
internal static BigInteger ArithmeticUnits(DoubleDouble value)
|
||||
{
|
||||
return ArithmeticUnits(value._high) + ArithmeticUnits(value._low);
|
||||
}
|
||||
internal static BigInteger ArithmeticUnits(DoubleDouble value) => ArithmeticUnits(value._high) + ArithmeticUnits(value._low);
|
||||
|
||||
internal static BigInteger ArithmeticUnits(double value)
|
||||
{
|
||||
@@ -342,11 +321,9 @@ internal static class PreciseMathHelper
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private static DoubleDouble AddScalarBoundary(double high, double low, double value)
|
||||
{
|
||||
private static DoubleDouble AddScalarBoundary(double high, double low, double value) =>
|
||||
// As in AddScalar, high/low are normalized but a negated zero low is allowed.
|
||||
return ArithmeticFromRatio(ArithmeticUnits(high) + ArithmeticUnits(low) + ArithmeticUnits(value), BigInteger.One << 1074);
|
||||
}
|
||||
ArithmeticFromRatio(ArithmeticUnits(high) + ArithmeticUnits(low) + ArithmeticUnits(value), BigInteger.One << 1074);
|
||||
|
||||
// Round an exact rational to binary64, ties-to-even, including subnormal and
|
||||
// overflow boundaries. Denominator is positive; sign is retained on underflow.
|
||||
|
||||
@@ -43,8 +43,10 @@ Do not claim API completeness or accuracy beyond tested contracts.
|
||||
|
||||
Follow `.editorconfig`, not incidental style in unfinished code.
|
||||
|
||||
- Use file-scoped namespaces, explicit types rather than `var`, and block-bodied
|
||||
methods. Preserve the configured expression-bodied property/accessor preferences.
|
||||
- Use file-scoped namespaces and explicit types rather than `var`. Prefer
|
||||
expression-bodied methods and operators when the expression fits on one line;
|
||||
otherwise use block bodies. Preserve the configured expression-bodied preferences
|
||||
for other member kinds.
|
||||
- Use `_camelCase` for non-public instance fields, including internal fields;
|
||||
`s_camelCase` for non-public mutable static fields; PascalCase for member constants
|
||||
and static readonly fields. Method-local constants follow local-variable camelCase.
|
||||
|
||||
Reference in New Issue
Block a user