@@ -18,4 +18,9 @@
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="System.Numerics"/>
|
||||
<Using Include="Shouldly"/>
|
||||
<Using Include="Xunit"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class ArithmeticRangeTests
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
using System.Numerics;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class DoubleDoubleArithmeticTests
|
||||
@@ -332,6 +328,53 @@ public class DoubleDoubleArithmeticTests
|
||||
Check(6.0 / new DoubleDouble(2.0), 3.0, 0.0);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(2.0)]
|
||||
[InlineData(3.0)]
|
||||
public void ScalarAdditionAndSubtractionRetainTheMiddleSumResidual(double magnitude)
|
||||
{
|
||||
// Exact Fraction arithmetic on the stored E components confirms that
|
||||
// all signed E +/- 2 and E +/- 3 results fit exactly in two components.
|
||||
// Compare exact dyadic sums, not another overload or a rounded tolerance.
|
||||
foreach (double valueSign in new[] { -1.0, 1.0 })
|
||||
{
|
||||
foreach (double scalarSign in new[] { -1.0, 1.0 })
|
||||
{
|
||||
DoubleDouble value = valueSign * DoubleDouble.E;
|
||||
double scalar = scalarSign * magnitude;
|
||||
BigInteger expectedSum = Units(value) + Units(scalar);
|
||||
BigInteger expectedDifference = Units(value) - Units(scalar);
|
||||
Units(value + scalar).ShouldBe(expectedSum);
|
||||
Units(scalar + value).ShouldBe(expectedSum);
|
||||
Units(value - scalar).ShouldBe(expectedDifference);
|
||||
Units(scalar - value).ShouldBe(-expectedDifference);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("+")]
|
||||
[InlineData("-")]
|
||||
public void ScalarSumsAndDifferencesMatchExpansionBitsAcrossRanges(string operation)
|
||||
{
|
||||
// Bitwise compatibility; independent exact-rational accuracy checks are separate.
|
||||
(double[] scalars, DoubleDouble[] values) = ScalarArithmeticCompatibilityCases();
|
||||
foreach (DoubleDouble value in values)
|
||||
{
|
||||
foreach (double scalar in scalars)
|
||||
{
|
||||
DoubleDouble expanded = new(scalar);
|
||||
DoubleDouble expected = operation == "+" ? value + expanded : value - expanded;
|
||||
DoubleDouble actual = operation == "+" ? value + scalar : value - scalar;
|
||||
CheckBoundary(actual, expected.High, expected.Low);
|
||||
|
||||
DoubleDouble expectedReverse = operation == "+" ? expanded + value : expanded - value;
|
||||
DoubleDouble actualReverse = operation == "+" ? scalar + value : scalar - value;
|
||||
CheckBoundary(actualReverse, expectedReverse.High, expectedReverse.Low);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExpansionCancellationRetainsExactComponentsAcrossTheAdditionGuard()
|
||||
{
|
||||
@@ -579,6 +622,25 @@ public class DoubleDoubleArithmeticTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DivisionOverloadsPreserveComponentBitsAcrossRangesAndSpecialValues()
|
||||
{
|
||||
// Compatibility, not an accuracy oracle. GeneralArithmeticMeetsExactRationalBound
|
||||
// separately checks complete results against exact rational bounds.
|
||||
(double[] scalars, DoubleDouble[] values) = ScalarArithmeticCompatibilityCases();
|
||||
foreach (DoubleDouble value in values)
|
||||
{
|
||||
foreach (double scalar in scalars)
|
||||
{
|
||||
DoubleDouble expectedQuotient = value / new DoubleDouble(scalar);
|
||||
CheckBoundary(value / scalar, expectedQuotient.High, expectedQuotient.Low);
|
||||
|
||||
DoubleDouble expectedReverseQuotient = new DoubleDouble(scalar) / value;
|
||||
CheckBoundary(scalar / value, expectedReverseQuotient.High, expectedReverseQuotient.Low);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DivisionRetainsSubnormalCorrectionsWithOrdinaryHighComponents()
|
||||
{
|
||||
@@ -597,6 +659,38 @@ public class DoubleDoubleArithmeticTests
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(-1000)]
|
||||
[InlineData(-1021)]
|
||||
[InlineData(-1022)]
|
||||
[InlineData(-1023)]
|
||||
public void ScalarDivisionPreservesSparseCorrectionProductsNearUnderflow(int lowExponent)
|
||||
{
|
||||
// At -1000, the second product is normal but its exact residual is
|
||||
// (962132647665515 / 1073741824) * epsilon, which rounds to 896056 * epsilon.
|
||||
// Derived from exact binary64 rational products; the other rows bracket
|
||||
// the correction product's normal/subnormal transition.
|
||||
foreach (double numeratorSign in new[] { -1.0, 1.0 })
|
||||
{
|
||||
foreach (double denominatorSign in new[] { -1.0, 1.0 })
|
||||
{
|
||||
foreach (double lowSign in new[] { -1.0, 1.0 })
|
||||
{
|
||||
double low = Math.ScaleB(lowSign, lowExponent);
|
||||
double denominator = denominatorSign * 1.1;
|
||||
DoubleDouble numerator = DoubleDouble.FromComponents(numeratorSign * 1.1, low);
|
||||
DoubleDouble actual = numerator / denominator;
|
||||
DoubleDouble expanded = numerator / new DoubleDouble(denominator);
|
||||
CheckBoundary(actual, expanded.High, expanded.Low);
|
||||
// Exact quotient = +/-1 + low/denominator. Its high cannot
|
||||
// change here; binary64 division independently rounds the low.
|
||||
CheckBoundary(actual, numeratorSign / denominatorSign, low / denominator);
|
||||
AssertRelative(actual, Units(numerator) << 1074, Units(denominator));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SubnormalProductsWithLargeNormalsRetainExactResultsInBothOrders()
|
||||
{
|
||||
@@ -884,6 +978,39 @@ public class DoubleDoubleArithmeticTests
|
||||
}
|
||||
}
|
||||
|
||||
private static (double[] Scalars, DoubleDouble[] Values) ScalarArithmeticCompatibilityCases()
|
||||
{
|
||||
List<double> scalars = [0.0, -0.0, 1.0, -1.0, 2.0, -2.0, 3.0, -3.0, 100.0, -100.0,
|
||||
double.MaxValue, double.MinValue, double.PositiveInfinity,
|
||||
double.NegativeInfinity, double.NaN];
|
||||
List<DoubleDouble> values = [DoubleDouble.E, -DoubleDouble.E];
|
||||
// Include addition/division dispatch edges, exponent extremes, dense/sparse
|
||||
// lows of either sign, and significands on either side of a binade.
|
||||
int[] exponents = [-1074, -1022, -451, -450, -1, 0, 1, 450, 451, 1020, 1021, 1023];
|
||||
double[] significands = [1.0, Math.BitIncrement(1.0), 1.5, Math.BitDecrement(2.0)];
|
||||
foreach (int exponent in exponents)
|
||||
{
|
||||
foreach (double significand in significands)
|
||||
{
|
||||
foreach (double sign in new[] { -1.0, 1.0 })
|
||||
{
|
||||
double high = Math.ScaleB(sign * significand, exponent);
|
||||
scalars.Add(high);
|
||||
double denseLow = Math.ScaleB(1.0, exponent - 54);
|
||||
foreach (double low in new[] { 0.0, denseLow, -denseLow, double.Epsilon, -double.Epsilon })
|
||||
{
|
||||
values.Add(DoubleDouble.FromComponents(high, low));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (double scalar in scalars)
|
||||
{
|
||||
values.Add(new DoubleDouble(scalar));
|
||||
}
|
||||
return (scalars.ToArray(), values.ToArray());
|
||||
}
|
||||
|
||||
private static void AssertDivisionMatchesPrevious(DoubleDouble left, DoubleDouble right)
|
||||
{
|
||||
// Freeze the pre-specialization expression. The unchanged public operators
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
using System.Numerics;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class DoubleDoubleBoundaryTests
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
using System.Numerics;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class DoubleDoubleCbrtTests
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class DoubleDoubleComparisonTests
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
using System.Numerics;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class DoubleDoubleConversionTests
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using Just.PreciseMath.Tests.ReferenceData;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Globalization;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
using System.Numerics;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class DoubleDoubleHypotTests
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class DoubleDoubleRepresentationTests
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class DoubleDoubleRootFunctionsTests
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using Just.PreciseMath.Tests.ReferenceData;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
using System.Numerics;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class DoubleDoubleSignedNumberTests
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Globalization;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
using System.Numerics;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class DoubleDoubleTests
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Numerics;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using Just.PreciseMath.Tests.ReferenceData;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
using System.Numerics;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class PreciseMathInvSqrtTests
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using Just.PreciseMath.Tests.ReferenceData;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
using System.Numerics;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class PreciseMathPowTests
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class PreciseMathRealPowSpecialTests
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using Just.PreciseMath.Tests.ReferenceData;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
using System.Numerics;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class PreciseMathReciprocalTests
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
using System.Numerics;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class PreciseMathSqrtTests
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests;
|
||||
|
||||
public class PreciseMathTests
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests.ReferenceData;
|
||||
|
||||
// Generated by generate_exp.py; do not derive expected values from DD arithmetic.
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
// absolute; reference rounding uncertainty is bounded by 2^-350 relative.
|
||||
// Tiny corrections to 1/-1 below 120 digits are not component-retention oracles.
|
||||
// Signed zeros, infinities, NaNs, and enormous arguments are tested separately.
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests.ReferenceData;
|
||||
|
||||
internal static class ExponentialFunctionsReferenceData
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Generated by generate_log.py; do not hand-edit reference literals.
|
||||
// Exact binary64 sums; Decimal.ln at 450/650 digits, rounded to 120 digits.
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests.ReferenceData;
|
||||
|
||||
internal static class LogReferenceData
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Generated by generate_real_pow.py; do not hand-edit reference literals.
|
||||
// Exact binary64 sums; Decimal ln/exp at 450/650 digits, rounded to 120 digits.
|
||||
// Reference uncertainty is explicitly allowed as 2^-350 relative in the tests.
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests.ReferenceData;
|
||||
|
||||
internal static class RealPowReferenceData
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Generated by generate_rootn.py; do not hand-edit reference literals.
|
||||
// Exact component sums; Decimal ln/exp at 450/650 digits, rounded to 120 digits.
|
||||
using Xunit;
|
||||
|
||||
namespace Just.PreciseMath.Tests.ReferenceData;
|
||||
|
||||
internal static class RootNReferenceData
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace Just.PreciseMath.Tests.SanityChecks;
|
||||
|
||||
public class DoubleDoubleAdditionChecks
|
||||
{
|
||||
public static IEnumerable<TheoryDataRow<DoubleDouble, DoubleDouble, DoubleDouble>> ReferenceCases =>
|
||||
[
|
||||
(new DoubleDouble(1.0), new DoubleDouble(1.0), new DoubleDouble(2.0)),
|
||||
(new DoubleDouble(1.0), new DoubleDouble(2.0), new DoubleDouble(3.0)),
|
||||
(new DoubleDouble(1.25), new DoubleDouble(2.5), new DoubleDouble(3.75)),
|
||||
(new DoubleDouble(65535.0), new DoubleDouble(1.0), new DoubleDouble(65536.0)),
|
||||
(DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), DoubleDouble.Parse("-812563124576179134504", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(42.0)),
|
||||
(DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(127.0), DoubleDouble.Parse("812563124576179134673", System.Globalization.CultureInfo.InvariantCulture)),
|
||||
(DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(27.0), DoubleDouble.Parse("812563124576179134573", System.Globalization.CultureInfo.InvariantCulture)),
|
||||
(DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(2.70), DoubleDouble.Parse("812563124576179134548.7", System.Globalization.CultureInfo.InvariantCulture)),
|
||||
];
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ReferenceCases))]
|
||||
public void AdditionShouldProduceExpectedResults(DoubleDouble left, DoubleDouble right, DoubleDouble expected)
|
||||
{
|
||||
DoubleDouble result = left + right;
|
||||
|
||||
result.High.ShouldBe(expected.High);
|
||||
result.Low.ShouldBe(expected.Low);
|
||||
result.ShouldBe(expected);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
namespace Just.PreciseMath.Tests.SanityChecks;
|
||||
|
||||
public class DoubleDoubleArithmeticEqualityChecks
|
||||
{
|
||||
public static IEnumerable<TheoryDataRow<double>> ReferenceCases => [1.0, 2.0, 3.0, 100.0, 0.1, 0.5, 0.333333333333333333, -1.0, 1553.0, 1.0e+10];
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ReferenceCases))]
|
||||
public void AdditionShouldProduceIdenticalResults(double reference)
|
||||
{
|
||||
DoubleDouble testValue = DoubleDouble.E; // any value with full precision range used
|
||||
|
||||
DoubleDouble ddxdd_Result = testValue + (new DoubleDouble(reference));
|
||||
DoubleDouble ddxd_Result = testValue + reference;
|
||||
DoubleDouble dxdd_Result = reference + testValue;
|
||||
|
||||
ddxdd_Result.High.ShouldBe(ddxd_Result.High);
|
||||
ddxdd_Result.Low.ShouldBe(ddxd_Result.Low);
|
||||
ddxdd_Result.ShouldBe(ddxd_Result);
|
||||
|
||||
ddxdd_Result.High.ShouldBe(dxdd_Result.High);
|
||||
ddxdd_Result.Low.ShouldBe(dxdd_Result.Low);
|
||||
ddxdd_Result.ShouldBe(dxdd_Result);
|
||||
|
||||
ddxd_Result.High.ShouldBe(dxdd_Result.High);
|
||||
ddxd_Result.Low.ShouldBe(dxdd_Result.Low);
|
||||
ddxd_Result.ShouldBe(dxdd_Result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ReferenceCases))]
|
||||
public void SubtractionFromShouldProduceIdenticalResults(double reference)
|
||||
{
|
||||
DoubleDouble testValue = DoubleDouble.E; // any value with full precision range used
|
||||
|
||||
DoubleDouble ddxdd_Result = testValue - (new DoubleDouble(reference));
|
||||
DoubleDouble ddxd_Result = testValue - reference;
|
||||
|
||||
ddxdd_Result.High.ShouldBe(ddxd_Result.High);
|
||||
ddxdd_Result.Low.ShouldBe(ddxd_Result.Low);
|
||||
ddxdd_Result.ShouldBe(ddxd_Result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ReferenceCases))]
|
||||
public void SubtractionShouldProduceIdenticalResults(double reference)
|
||||
{
|
||||
DoubleDouble testValue = DoubleDouble.E; // any value with full precision range used
|
||||
|
||||
DoubleDouble ddxdd_Result = (new DoubleDouble(reference)) - testValue;
|
||||
DoubleDouble dxdd_Result = reference - testValue;
|
||||
|
||||
ddxdd_Result.High.ShouldBe(dxdd_Result.High);
|
||||
ddxdd_Result.Low.ShouldBe(dxdd_Result.Low);
|
||||
ddxdd_Result.ShouldBe(dxdd_Result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ReferenceCases))]
|
||||
public void MultiplicationShouldProduceIdenticalResults(double reference)
|
||||
{
|
||||
DoubleDouble testValue = DoubleDouble.E; // any value with full precision range used
|
||||
|
||||
DoubleDouble ddxdd_Result = testValue * (new DoubleDouble(reference));
|
||||
DoubleDouble ddxd_Result = testValue * reference;
|
||||
DoubleDouble dxdd_Result = reference * testValue;
|
||||
|
||||
ddxdd_Result.High.ShouldBe(ddxd_Result.High);
|
||||
ddxdd_Result.Low.ShouldBe(ddxd_Result.Low);
|
||||
ddxdd_Result.ShouldBe(ddxd_Result);
|
||||
|
||||
ddxdd_Result.High.ShouldBe(dxdd_Result.High);
|
||||
ddxdd_Result.Low.ShouldBe(dxdd_Result.Low);
|
||||
ddxdd_Result.ShouldBe(dxdd_Result);
|
||||
|
||||
ddxd_Result.High.ShouldBe(dxdd_Result.High);
|
||||
ddxd_Result.Low.ShouldBe(dxdd_Result.Low);
|
||||
ddxd_Result.ShouldBe(dxdd_Result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ReferenceCases))]
|
||||
public void DivisionShouldProduceIdenticalResults(double reference)
|
||||
{
|
||||
DoubleDouble testValue = DoubleDouble.E; // any value with full precision range used
|
||||
|
||||
DoubleDouble ddxdd_Result = testValue / (new DoubleDouble(reference));
|
||||
DoubleDouble ddxd_Result = testValue / reference;
|
||||
|
||||
ddxdd_Result.High.ShouldBe(ddxd_Result.High);
|
||||
ddxdd_Result.Low.ShouldBe(ddxd_Result.Low);
|
||||
ddxdd_Result.ShouldBe(ddxd_Result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ReferenceCases))]
|
||||
public void DivisionByShouldProduceIdenticalResults(double reference)
|
||||
{
|
||||
DoubleDouble testValue = DoubleDouble.E; // any value with full precision range used
|
||||
|
||||
DoubleDouble ddxdd_Result = (new DoubleDouble(reference)) / testValue;
|
||||
DoubleDouble dxdd_Result = reference / testValue;
|
||||
|
||||
ddxdd_Result.High.ShouldBe(dxdd_Result.High);
|
||||
ddxdd_Result.Low.ShouldBe(dxdd_Result.Low);
|
||||
ddxdd_Result.ShouldBe(dxdd_Result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace Just.PreciseMath.Tests.SanityChecks;
|
||||
|
||||
public class DoubleDoubleDivisionChecks
|
||||
{
|
||||
public static IEnumerable<TheoryDataRow<DoubleDouble, DoubleDouble, DoubleDouble>> ReferenceCases =>
|
||||
[
|
||||
(new DoubleDouble(6.0), new DoubleDouble(2.0), new DoubleDouble(3.0)),
|
||||
(new DoubleDouble(6.0), new DoubleDouble(3.0), new DoubleDouble(2.0)),
|
||||
(new DoubleDouble(5.0), new DoubleDouble(2.0), new DoubleDouble(2.5)),
|
||||
(new DoubleDouble(1.0), new DoubleDouble(4.0), new DoubleDouble(0.25)),
|
||||
(new DoubleDouble(3.75), new DoubleDouble(1.25), new DoubleDouble(3.0)),
|
||||
(new DoubleDouble(65536.0), new DoubleDouble(1024.0), new DoubleDouble(64.0)),
|
||||
(DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(2.0), DoubleDouble.Parse("406281562288089567273", System.Globalization.CultureInfo.InvariantCulture)),
|
||||
(DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(4.0), DoubleDouble.Parse("203140781144044783636.5", System.Globalization.CultureInfo.InvariantCulture)),
|
||||
(DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(8.0), DoubleDouble.Parse("101570390572022391818.25", System.Globalization.CultureInfo.InvariantCulture)),
|
||||
(DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(1.0)),
|
||||
];
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ReferenceCases))]
|
||||
public void DivisionShouldProduceExpectedResults(DoubleDouble left, DoubleDouble right, DoubleDouble expected)
|
||||
{
|
||||
DoubleDouble result = left / right;
|
||||
|
||||
result.High.ShouldBe(expected.High);
|
||||
result.Low.ShouldBe(expected.Low);
|
||||
result.ShouldBe(expected);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace Just.PreciseMath.Tests.SanityChecks;
|
||||
|
||||
public class DoubleDoubleMultiplicationChecks
|
||||
{
|
||||
public static IEnumerable<TheoryDataRow<DoubleDouble, DoubleDouble, DoubleDouble>> ReferenceCases =>
|
||||
[
|
||||
(new DoubleDouble(1.0), new DoubleDouble(1.0), new DoubleDouble(1.0)),
|
||||
(new DoubleDouble(2.0), new DoubleDouble(3.0), new DoubleDouble(6.0)),
|
||||
(new DoubleDouble(1.25), new DoubleDouble(2.5), new DoubleDouble(3.125)),
|
||||
(new DoubleDouble(-1.25), new DoubleDouble(2.5), new DoubleDouble(-3.125)),
|
||||
(new DoubleDouble(65535.0), new DoubleDouble(65536.0), new DoubleDouble(4294901760.0)),
|
||||
(new DoubleDouble(65536.0), new DoubleDouble(65536.0), new DoubleDouble(4294967296.0)),
|
||||
(DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(2.0), DoubleDouble.Parse("1625126249152358269092", System.Globalization.CultureInfo.InvariantCulture)),
|
||||
(DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(0.5), DoubleDouble.Parse("406281562288089567273", System.Globalization.CultureInfo.InvariantCulture)),
|
||||
(DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(27.0), DoubleDouble.Parse("21939204363556836632742", System.Globalization.CultureInfo.InvariantCulture)),
|
||||
(DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(127.0), DoubleDouble.Parse("103195516821174750087342", System.Globalization.CultureInfo.InvariantCulture)),
|
||||
];
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ReferenceCases))]
|
||||
public void MultiplicationShouldProduceExpectedResults(DoubleDouble left, DoubleDouble right, DoubleDouble expected)
|
||||
{
|
||||
DoubleDouble result = left * right;
|
||||
|
||||
result.High.ShouldBe(expected.High);
|
||||
result.Low.ShouldBe(expected.Low);
|
||||
result.ShouldBe(expected);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace Just.PreciseMath.Tests.SanityChecks;
|
||||
|
||||
public class DoubleDoubleSubtractionChecks
|
||||
{
|
||||
public static IEnumerable<TheoryDataRow<DoubleDouble, DoubleDouble, DoubleDouble>> ReferenceCases =>
|
||||
[
|
||||
(new DoubleDouble(2.0), new DoubleDouble(1.0), new DoubleDouble(1.0)),
|
||||
(new DoubleDouble(1.0), new DoubleDouble(2.0), new DoubleDouble(-1.0)),
|
||||
(new DoubleDouble(3.75), new DoubleDouble(2.5), new DoubleDouble(1.25)),
|
||||
(new DoubleDouble(2.5), new DoubleDouble(3.75), new DoubleDouble(-1.25)),
|
||||
(new DoubleDouble(65536.0), new DoubleDouble(1.0), new DoubleDouble(65535.0)),
|
||||
(new DoubleDouble(65536.0), new DoubleDouble(65535.0), new DoubleDouble(1.0)),
|
||||
(DoubleDouble.Parse("812563124576179134673", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(127.0), DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture)),
|
||||
(DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(127.0), DoubleDouble.Parse("812563124576179134419", System.Globalization.CultureInfo.InvariantCulture)),
|
||||
(DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), DoubleDouble.Parse("812563124576179134504", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(42.0)),
|
||||
(DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(0.5), DoubleDouble.Parse("812563124576179134545.5", System.Globalization.CultureInfo.InvariantCulture)),
|
||||
(DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), DoubleDouble.Parse("812563124576179134546", System.Globalization.CultureInfo.InvariantCulture), new DoubleDouble(0.0)),
|
||||
];
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ReferenceCases))]
|
||||
public void SubtractionShouldProduceExpectedResults(DoubleDouble left, DoubleDouble right, DoubleDouble expected)
|
||||
{
|
||||
DoubleDouble result = left - right;
|
||||
|
||||
result.High.ShouldBe(expected.High);
|
||||
result.Low.ShouldBe(expected.Low);
|
||||
result.ShouldBe(expected);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user