modulus implementation
.NET Test / .NET tests (push) Successful in 2m8s

This commit is contained in:
2026-09-24 02:25:35 +04:00
parent cb06df8865
commit 4a7ce1b8ed
7 changed files with 646 additions and 8 deletions
@@ -0,0 +1,99 @@
namespace Just.PreciseMath.Tests;
public class DoubleDoubleNumberTests
{
[Fact]
public void NumberDefaultsUseBothComponents()
{
DoubleDouble lower = new(1.0, -double.Epsilon);
DoubleDouble upper = new(1.0, double.Epsilon);
AssertBits(Max(lower, upper), upper);
AssertBits(Max(upper, lower), upper);
AssertBits(MaxNumber(lower, upper), upper);
AssertBits(Min(lower, upper), lower);
AssertBits(Min(upper, lower), lower);
AssertBits(MinNumber(lower, upper), lower);
AssertBits(Clamp(DoubleDouble.Zero, lower, upper), lower);
AssertBits(Clamp(DoubleDouble.One, lower, upper), DoubleDouble.One);
AssertBits(Clamp(new DoubleDouble(2.0), lower, upper), upper);
Should.Throw<ArgumentException>(() => Clamp(DoubleDouble.One, upper, lower));
AssertBits(CopySign(upper, DoubleDouble.NegativeZero), new DoubleDouble(-1.0, -double.Epsilon));
AssertBits(CopySign(-upper, DoubleDouble.Zero), upper);
Sign(lower).ShouldBe(1);
Sign(-upper).ShouldBe(-1);
}
[Fact]
public void NumberDefaultsHandleSpecialValuesAndSignedZeros()
{
double[] values = [0.0, -0.0, 1.0, -1.0, double.Epsilon, -double.Epsilon,
double.MaxValue, double.PositiveInfinity, double.NegativeInfinity, double.NaN];
foreach (double left in values)
{
DoubleDouble x = new(left);
foreach (double right in values)
{
DoubleDouble y = new(right);
AssertBits(Max(x, y), new DoubleDouble(double.Max(left, right)));
AssertBits(Min(x, y), new DoubleDouble(double.Min(left, right)));
AssertBits(MaxNumber(x, y), new DoubleDouble(double.MaxNumber(left, right)));
AssertBits(MinNumber(x, y), new DoubleDouble(double.MinNumber(left, right)));
AssertBits(CopySign(x, y), new DoubleDouble(double.CopySign(left, right)));
}
AssertBits(Clamp(x, DoubleDouble.NegativeOne, DoubleDouble.One), new DoubleDouble(double.Clamp(left, -1.0, 1.0)));
if (double.IsNaN(left))
{
Should.Throw<ArithmeticException>(() => Sign(x));
Should.Throw<ArithmeticException>(() => DoubleDouble.Sign(x));
}
else
{
Sign(x).ShouldBe(double.Sign(left));
DoubleDouble.Sign(x).ShouldBe(double.Sign(left));
}
}
}
#if NET10_0_OR_GREATER
[Fact]
public void NativeDefaultsRetainFullComponentOrdering()
{
DoubleDouble lower = new(1.0, -double.Epsilon);
DoubleDouble upper = new(1.0, double.Epsilon);
AssertBits(MaxNative(lower, upper), upper);
AssertBits(MinNative(lower, upper), lower);
AssertBits(ClampNative(DoubleDouble.Zero, lower, upper), lower);
AssertBits(ClampNative(DoubleDouble.One, lower, upper), DoubleDouble.One);
AssertBits(ClampNative(new DoubleDouble(2.0), lower, upper), upper);
Should.Throw<ArgumentException>(() => ClampNative(DoubleDouble.One, upper, lower));
}
#endif
private static T Clamp<T>(T value, T min, T max) where T : INumber<T> => T.Clamp(value, min, max);
private static T CopySign<T>(T value, T sign) where T : INumber<T> => T.CopySign(value, sign);
private static T Max<T>(T x, T y) where T : INumber<T> => T.Max(x, y);
private static T MaxNumber<T>(T x, T y) where T : INumber<T> => T.MaxNumber(x, y);
private static T Min<T>(T x, T y) where T : INumber<T> => T.Min(x, y);
private static T MinNumber<T>(T x, T y) where T : INumber<T> => T.MinNumber(x, y);
private static int Sign<T>(T value) where T : INumber<T> => T.Sign(value);
#if NET10_0_OR_GREATER
private static T ClampNative<T>(T value, T min, T max) where T : INumber<T> => T.ClampNative(value, min, max);
private static T MaxNative<T>(T x, T y) where T : INumber<T> => T.MaxNative(x, y);
private static T MinNative<T>(T x, T y) where T : INumber<T> => T.MinNative(x, y);
#endif
private static void AssertBits(DoubleDouble actual, DoubleDouble expected)
{
BitConverter.DoubleToInt64Bits(actual.High).ShouldBe(BitConverter.DoubleToInt64Bits(expected.High));
BitConverter.DoubleToInt64Bits(actual.Low).ShouldBe(BitConverter.DoubleToInt64Bits(expected.Low));
}
}