one-liners use expression body
.NET Test / .NET tests (push) Successful in 2m15s

This commit is contained in:
2026-09-24 00:57:02 +04:00
parent ac93744579
commit 720fd1e21f
15 changed files with 121 additions and 424 deletions
@@ -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>
+2 -8
View File
@@ -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);
}
+9 -32
View File
@@ -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.