implemented ISignedNumber
.NET Test / .NET tests (push) Successful in 4m27s

This commit is contained in:
2026-09-13 23:08:27 +04:00
parent 082fd84c87
commit e51874b0c3
13 changed files with 1286 additions and 43 deletions
@@ -0,0 +1,108 @@
using System.Globalization;
using System.Numerics;
using Shouldly;
using Xunit;
namespace Just.PreciseMath.Tests;
public class DoubleDoubleSpecialValueTests
{
[Theory]
[InlineData("+NaN")]
[InlineData("-NaN")]
[InlineData("+Infinity")]
[InlineData("-Infinity")]
[InlineData(" NaN ")]
[InlineData(" \t+Infinity\r\n")]
public void StandardSpecialValuesMatchBinary64WithoutStyleFlags(string text)
{
double.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out double expected).ShouldBeTrue();
AssertAllParsers(text, CultureInfo.InvariantCulture, expected);
}
[Theory]
[InlineData("inf", double.PositiveInfinity)]
[InlineData("+INF", double.PositiveInfinity)]
[InlineData("-iNf", double.NegativeInfinity)]
[InlineData(" \t-inf\r\n", double.NegativeInfinity)]
public void ShortInfinityAliasIsCaseInsensitive(string text, double expected)
{
AssertAllParsers(text, CultureInfo.InvariantCulture, expected);
}
[Fact]
public void ShortInfinityUsesCultureSignsAndRespectsCustomSymbolPrecedence()
{
NumberFormatInfo info = new() { PositiveSign = "plus", NegativeSign = "minus" };
AssertAllParsers(" minusINF ", info, double.NegativeInfinity);
AssertAllParsers("plusinf", info, double.PositiveInfinity);
info.NaNSymbol = "inf";
AssertAllParsers("inf", info, double.NaN);
info.NaNSymbol = "missing";
info.NegativeInfinitySymbol = "inf";
AssertAllParsers("inf", info, double.NegativeInfinity);
}
[Theory]
[InlineData("in")]
[InlineData("infx")]
[InlineData("infinite")]
[InlineData("--inf")]
[InlineData("+ inf")]
[InlineData("inf-")]
public void MalformedAliasesAreRejected(string text)
{
DoubleDouble.TryParse(text, CultureInfo.InvariantCulture, out DoubleDouble result).ShouldBeFalse();
result.ShouldBe(DoubleDouble.Zero);
DoubleDouble.TryParse(text.AsSpan(), NumberStyles.Any, CultureInfo.InvariantCulture, out result).ShouldBeFalse();
result.ShouldBe(DoubleDouble.Zero);
}
[Fact]
public void SpecialValuesStillRespectRawLengthAndInvalidStyles()
{
AssertAllParsers(new string(' ', 2045) + "inf", CultureInfo.InvariantCulture, double.PositiveInfinity);
string tooLong = new string(' ', 2046) + "inf";
DoubleDouble.TryParse(tooLong, CultureInfo.InvariantCulture, out _).ShouldBeFalse();
DoubleDouble.TryParse(tooLong.AsSpan(), NumberStyles.None, CultureInfo.InvariantCulture, out _).ShouldBeFalse();
Should.Throw<FormatException>(() => DoubleDouble.Parse(tooLong, NumberStyles.None, CultureInfo.InvariantCulture));
Should.Throw<ArgumentException>(() => DoubleDouble.TryParse("inf", NumberStyles.HexNumber, null, out _));
DoubleDouble.TryParse(" +1 ", NumberStyles.None, CultureInfo.InvariantCulture, out _).ShouldBeFalse();
}
[Fact]
public void AbsCanonicalizesRawNaNPayloadsOfEitherSign()
{
foreach (long bits in new[] { 0x7ff8000000000001L, unchecked((long)0xfff8000000000001UL) })
{
DoubleDouble result = DoubleDouble.Abs(new DoubleDouble(BitConverter.Int64BitsToDouble(bits), 0.0));
BitConverter.DoubleToInt64Bits(result.High).ShouldBe(BitConverter.DoubleToInt64Bits(double.NaN));
BitConverter.DoubleToInt64Bits(result.Low).ShouldBe(0L);
DoubleDouble.IsCanonical(result).ShouldBeTrue();
}
}
private static void AssertAllParsers(string text, IFormatProvider provider, double expected)
{
DoubleDouble.TryParse(text, provider, out DoubleDouble fromString).ShouldBeTrue();
DoubleDouble.TryParse(text.AsSpan(), provider, out DoubleDouble fromSpan).ShouldBeTrue();
DoubleDouble[] values = [fromString, fromSpan, DoubleDouble.Parse(text, provider), DoubleDouble.Parse(text.AsSpan(), provider),
ParseStyled<DoubleDouble>(text, provider)];
foreach (DoubleDouble value in values)
{
BitConverter.DoubleToInt64Bits(value.High).ShouldBe(BitConverter.DoubleToInt64Bits(expected));
BitConverter.DoubleToInt64Bits(value.Low).ShouldBe(0L);
}
}
private static T ParseStyled<T>(string text, IFormatProvider provider) where T : INumberBase<T>
{
T.TryParse(text, NumberStyles.None, provider, out T? fromString).ShouldBeTrue();
T.TryParse(text.AsSpan(), NumberStyles.None, provider, out T? fromSpan).ShouldBeTrue();
T result = T.Parse(text, NumberStyles.None, provider);
fromString.ShouldBe(result);
fromSpan.ShouldBe(result);
T.Parse(text.AsSpan(), NumberStyles.None, provider).ShouldBe(result);
return result;
}
}