This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user