using Shouldly; using Xunit; namespace Just.PreciseMath.Tests; public class PreciseMathTests { [Fact] public void AbsPreservesBothComponentsAndCanonicalSpecialValues() { double[] scalars = [0.0, -0.0, 1.0, -1.0, double.Epsilon, -double.Epsilon, double.MaxValue, double.MinValue, double.PositiveInfinity, double.NegativeInfinity, double.NaN]; foreach (double scalar in scalars) { // Binary64 is an independent reference when the input has no residual. DoubleDouble actual = DDMath.Abs(new DoubleDouble(scalar)); AssertBits(actual, double.IsNaN(scalar) ? double.NaN : Math.Abs(scalar), 0.0); DoubleDouble.IsCanonical(actual).ShouldBeTrue(); } foreach (double low in new[] { Math.ScaleB(1.0, -54), -Math.ScaleB(1.0, -54), double.Epsilon, -double.Epsilon }) { DoubleDouble positive = DoubleDouble.FromComponents(1.0, low); DoubleDouble negative = DoubleDouble.FromComponents(-1.0, -low); AssertBits(DDMath.Abs(positive), 1.0, low); AssertBits(DDMath.Abs(negative), 1.0, low); } } private static void AssertBits(DoubleDouble actual, double high, double low) { BitConverter.DoubleToInt64Bits(actual.High).ShouldBe(BitConverter.DoubleToInt64Bits(high)); BitConverter.DoubleToInt64Bits(actual.Low).ShouldBe(BitConverter.DoubleToInt64Bits(low)); } }