From 053c7a344a1dc3d17e4e99bd3419fb1cf024aedc Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Tue, 15 Nov 2022 16:46:28 -0600 Subject: [PATCH 01/39] Add IDecimalFloatingPointIEE754 and Decimal32 --- .../Numerics/IDecimalFloatingPointIeee754.cs | 26 +++ .../src/System/Numerics/Decimal32.cs | 163 ++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Numerics/IDecimalFloatingPointIeee754.cs create mode 100644 src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/IDecimalFloatingPointIeee754.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/IDecimalFloatingPointIeee754.cs new file mode 100644 index 00000000000000..d5295412b3d19c --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/IDecimalFloatingPointIeee754.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Numerics +{ + /// Defines an IEEE 754 floating-point type that is represented in a base-10 format. + /// The type that implements the interface. + public interface IDecimalFloatingPointIeee754 + : IFloatingPointIeee754 + where TSelf : IDecimalFloatingPointIeee754 + { + // 5.3.2 + static abstract TSelf Quantize(TSelf x, TSelf y); + static abstract TSelf Quantum(TSelf x); + + // 5.5.2 + // TODO put these in BitConverter +/* TOther EncodeDecimal(TSelf x); + TSelf DecodeDecimal(TOther x); + TOther EncodeBinary(TSelf x); + TSelf DecodeBinary(TOther x);*/ + + // 5.7.3 + static abstract bool SameQuantum(TSelf x, TSelf y); + } +} diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs new file mode 100644 index 00000000000000..72960086aab846 --- /dev/null +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -0,0 +1,163 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace System.Numerics +{ + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public readonly struct Decimal32 + : IComparable, + IComparable, + ISpanFormattable, + ISpanParsable, + IEquatable, + IConvertible, + IDecimalFloatingPointIeee754, + IMinMaxValue + { + private readonly uint _value; + + public static Decimal32 Epsilon => throw new NotImplementedException(); + + public static Decimal32 NaN => throw new NotImplementedException(); + + public static Decimal32 NegativeInfinity => throw new NotImplementedException(); + + public static Decimal32 NegativeZero => throw new NotImplementedException(); + + public static Decimal32 PositiveInfinity => throw new NotImplementedException(); + + public static Decimal32 NegativeOne => throw new NotImplementedException(); + + public static Decimal32 E => throw new NotImplementedException(); + + public static Decimal32 Pi => throw new NotImplementedException(); + + public static Decimal32 Tau => throw new NotImplementedException(); + + public static Decimal32 One => throw new NotImplementedException(); + + public static int Radix => throw new NotImplementedException(); + + public static Decimal32 Zero => throw new NotImplementedException(); + + public static Decimal32 AdditiveIdentity => throw new NotImplementedException(); + + public static Decimal32 MultiplicativeIdentity => throw new NotImplementedException(); + + public static Decimal32 Abs(Decimal32 value) => throw new NotImplementedException(); + public static Decimal32 Acos(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Acosh(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 AcosPi(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Asin(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Asinh(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 AsinPi(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Atan(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Atan2(Decimal32 y, Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Atan2Pi(Decimal32 y, Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Atanh(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 AtanPi(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 BitDecrement(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 BitIncrement(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Cbrt(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Cos(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Cosh(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 CosPi(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Exp(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Exp10(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Exp2(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 FusedMultiplyAdd(Decimal32 left, Decimal32 right, Decimal32 addend) => throw new NotImplementedException(); + public static Decimal32 Hypot(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + public static Decimal32 Ieee754Remainder(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + public static int ILogB(Decimal32 x) => throw new NotImplementedException(); + public static bool IsCanonical(Decimal32 value) => throw new NotImplementedException(); + public static bool IsComplexNumber(Decimal32 value) => throw new NotImplementedException(); + public static bool IsEvenInteger(Decimal32 value) => throw new NotImplementedException(); + public static bool IsFinite(Decimal32 value) => throw new NotImplementedException(); + public static bool IsImaginaryNumber(Decimal32 value) => throw new NotImplementedException(); + public static bool IsInfinity(Decimal32 value) => throw new NotImplementedException(); + public static bool IsInteger(Decimal32 value) => throw new NotImplementedException(); + public static bool IsNaN(Decimal32 value) => throw new NotImplementedException(); + public static bool IsNegative(Decimal32 value) => throw new NotImplementedException(); + public static bool IsNegativeInfinity(Decimal32 value) => throw new NotImplementedException(); + public static bool IsNormal(Decimal32 value) => throw new NotImplementedException(); + public static bool IsOddInteger(Decimal32 value) => throw new NotImplementedException(); + public static bool IsPositive(Decimal32 value) => throw new NotImplementedException(); + public static bool IsPositiveInfinity(Decimal32 value) => throw new NotImplementedException(); + public static bool IsRealNumber(Decimal32 value) => throw new NotImplementedException(); + public static bool IsSubnormal(Decimal32 value) => throw new NotImplementedException(); + public static bool IsZero(Decimal32 value) => throw new NotImplementedException(); + public static Decimal32 Log(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Log(Decimal32 x, Decimal32 newBase) => throw new NotImplementedException(); + public static Decimal32 Log10(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Log2(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 MaxMagnitude(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + public static Decimal32 MaxMagnitudeNumber(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + public static Decimal32 MinMagnitude(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + public static Decimal32 MinMagnitudeNumber(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + public static Decimal32 Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider) => throw new NotImplementedException(); + public static Decimal32 Parse(string s, NumberStyles style, IFormatProvider? provider) => throw new NotImplementedException(); + public static Decimal32 Parse(ReadOnlySpan s, IFormatProvider? provider) => throw new NotImplementedException(); + public static Decimal32 Parse(string s, IFormatProvider? provider) => throw new NotImplementedException(); + public static Decimal32 Pow(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + public static Decimal32 Quantize(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + public static Decimal32 Quantum(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 RootN(Decimal32 x, int n) => throw new NotImplementedException(); + public static Decimal32 Round(Decimal32 x, int digits, MidpointRounding mode) => throw new NotImplementedException(); + public static bool SameQuantum(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + public static Decimal32 ScaleB(Decimal32 x, int n) => throw new NotImplementedException(); + public static Decimal32 Sin(Decimal32 x) => throw new NotImplementedException(); + public static (Decimal32 Sin, Decimal32 Cos) SinCos(Decimal32 x) => throw new NotImplementedException(); + public static (Decimal32 SinPi, Decimal32 CosPi) SinCosPi(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Sinh(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 SinPi(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Sqrt(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Tan(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Tanh(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 TanPi(Decimal32 x) => throw new NotImplementedException(); + public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); + static bool INumberBase.TryConvertFromChecked(TOther value, out Decimal32 result) => throw new NotImplementedException(); + static bool INumberBase.TryConvertFromSaturating(TOther value, out Decimal32 result) => throw new NotImplementedException(); + static bool INumberBase.TryConvertFromTruncating(TOther value, out Decimal32 result) => throw new NotImplementedException(); + static bool INumberBase.TryConvertToChecked(Decimal32 value, out TOther result) => throw new NotImplementedException(); + static bool INumberBase.TryConvertToSaturating(Decimal32 value, out TOther result) => throw new NotImplementedException(); + static bool INumberBase.TryConvertToTruncating(Decimal32 value, out TOther result) => throw new NotImplementedException(); + public int CompareTo(object? obj) => throw new NotImplementedException(); + public int CompareTo(Decimal32 other) => throw new NotImplementedException(); + public bool Equals(Decimal32 other) => throw new NotImplementedException(); + public int GetExponentByteCount() => throw new NotImplementedException(); + public int GetExponentShortestBitLength() => throw new NotImplementedException(); + public int GetSignificandBitLength() => throw new NotImplementedException(); + public int GetSignificandByteCount() => throw new NotImplementedException(); + public string ToString(string? format, IFormatProvider? formatProvider) => throw new NotImplementedException(); + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) => throw new NotImplementedException(); + public bool TryWriteExponentBigEndian(Span destination, out int bytesWritten) => throw new NotImplementedException(); + public bool TryWriteExponentLittleEndian(Span destination, out int bytesWritten) => throw new NotImplementedException(); + public bool TryWriteSignificandBigEndian(Span destination, out int bytesWritten) => throw new NotImplementedException(); + public bool TryWriteSignificandLittleEndian(Span destination, out int bytesWritten) => throw new NotImplementedException(); + + public static Decimal32 operator +(Decimal32 value) => throw new NotImplementedException(); + public static Decimal32 operator +(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + public static Decimal32 operator -(Decimal32 value) => throw new NotImplementedException(); + public static Decimal32 operator -(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + public static Decimal32 operator ++(Decimal32 value) => throw new NotImplementedException(); + public static Decimal32 operator --(Decimal32 value) => throw new NotImplementedException(); + public static Decimal32 operator *(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + public static Decimal32 operator /(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + public static Decimal32 operator %(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + public static bool operator ==(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + public static bool operator !=(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + public static bool operator <(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + public static bool operator >(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + public static bool operator <=(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + public static bool operator >=(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + } +} From dcf9ca46cf539f27e8b0d1a7bc43cdf3d5f70d85 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Wed, 16 Nov 2022 12:12:27 -0600 Subject: [PATCH 02/39] fix initial Decimal32 surface, fix ref files --- .../ref/System.Runtime.Numerics.cs | 135 +++++++++++++++++- .../src/System/Numerics/Decimal32.cs | 31 ++-- .../System.Runtime/ref/System.Runtime.cs | 6 + 3 files changed, 162 insertions(+), 10 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs index 0d371c4d7886c6..dd63fe15427dce 100644 --- a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs +++ b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs @@ -194,10 +194,10 @@ namespace System.Numerics public static System.Numerics.BigInteger RotateLeft(System.Numerics.BigInteger value, int rotateAmount) { throw null; } public static System.Numerics.BigInteger RotateRight(System.Numerics.BigInteger value, int rotateAmount) { throw null; } public static System.Numerics.BigInteger Subtract(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; } - static bool System.Numerics.IBinaryInteger.TryReadBigEndian(System.ReadOnlySpan source, bool isUnsigned, out System.Numerics.BigInteger value) { throw null; } - static bool System.Numerics.IBinaryInteger.TryReadLittleEndian(System.ReadOnlySpan source, bool isUnsigned, out System.Numerics.BigInteger value) { throw null; } int System.Numerics.IBinaryInteger.GetByteCount() { throw null; } int System.Numerics.IBinaryInteger.GetShortestBitLength() { throw null; } + static bool System.Numerics.IBinaryInteger.TryReadBigEndian(System.ReadOnlySpan source, bool isUnsigned, out System.Numerics.BigInteger value) { throw null; } + static bool System.Numerics.IBinaryInteger.TryReadLittleEndian(System.ReadOnlySpan source, bool isUnsigned, out System.Numerics.BigInteger value) { throw null; } bool System.Numerics.IBinaryInteger.TryWriteBigEndian(System.Span destination, out int bytesWritten) { throw null; } bool System.Numerics.IBinaryInteger.TryWriteLittleEndian(System.Span destination, out int bytesWritten) { throw null; } static bool System.Numerics.INumberBase.IsCanonical(System.Numerics.BigInteger value) { throw null; } @@ -382,4 +382,135 @@ namespace System.Numerics public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Numerics.Complex result) { throw null; } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.IFormatProvider? provider, out System.Numerics.Complex result) { throw null; } } + public readonly partial struct Decimal32 : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable, System.IParsable, System.ISpanFormattable, System.ISpanParsable, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity, System.Numerics.IComparisonOperators, System.Numerics.IDecimalFloatingPointIeee754, System.Numerics.IDecrementOperators, System.Numerics.IDivisionOperators, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions, System.Numerics.IFloatingPoint, System.Numerics.IFloatingPointConstants, System.Numerics.IFloatingPointIeee754, System.Numerics.IHyperbolicFunctions, System.Numerics.IIncrementOperators, System.Numerics.ILogarithmicFunctions, System.Numerics.IMinMaxValue, System.Numerics.IModulusOperators, System.Numerics.IMultiplicativeIdentity, System.Numerics.IMultiplyOperators, System.Numerics.INumber, System.Numerics.INumberBase, System.Numerics.IPowerFunctions, System.Numerics.IRootFunctions, System.Numerics.ISignedNumber, System.Numerics.ISubtractionOperators, System.Numerics.ITrigonometricFunctions, System.Numerics.IUnaryNegationOperators, System.Numerics.IUnaryPlusOperators + { + private readonly int _dummyPrimitive; + public static System.Numerics.Decimal32 AdditiveIdentity { get { throw null; } } + public static System.Numerics.Decimal32 E { get { throw null; } } + public static System.Numerics.Decimal32 Epsilon { get { throw null; } } + public static System.Numerics.Decimal32 MaxValue { get { throw null; } } + public static System.Numerics.Decimal32 MinValue { get { throw null; } } + public static System.Numerics.Decimal32 MultiplicativeIdentity { get { throw null; } } + public static System.Numerics.Decimal32 NaN { get { throw null; } } + public static System.Numerics.Decimal32 NegativeInfinity { get { throw null; } } + public static System.Numerics.Decimal32 NegativeOne { get { throw null; } } + public static System.Numerics.Decimal32 NegativeZero { get { throw null; } } + public static System.Numerics.Decimal32 One { get { throw null; } } + public static System.Numerics.Decimal32 Pi { get { throw null; } } + public static System.Numerics.Decimal32 PositiveInfinity { get { throw null; } } + public static int Radix { get { throw null; } } + public static System.Numerics.Decimal32 Tau { get { throw null; } } + public static System.Numerics.Decimal32 Zero { get { throw null; } } + public static System.Numerics.Decimal32 Abs(System.Numerics.Decimal32 value) { throw null; } + public static System.Numerics.Decimal32 Acos(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Acosh(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 AcosPi(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Asin(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Asinh(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 AsinPi(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Atan(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Atan2(System.Numerics.Decimal32 y, System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Atan2Pi(System.Numerics.Decimal32 y, System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Atanh(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 AtanPi(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 BitDecrement(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 BitIncrement(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Cbrt(System.Numerics.Decimal32 x) { throw null; } + public int CompareTo(System.Numerics.Decimal32 other) { throw null; } + public int CompareTo(object? obj) { throw null; } + public static System.Numerics.Decimal32 Cos(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Cosh(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 CosPi(System.Numerics.Decimal32 x) { throw null; } + public bool Equals(System.Numerics.Decimal32 other) { throw null; } + public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } + public static System.Numerics.Decimal32 Exp(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Exp10(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Exp2(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 FusedMultiplyAdd(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right, System.Numerics.Decimal32 addend) { throw null; } + public int GetExponentByteCount() { throw null; } + public int GetExponentShortestBitLength() { throw null; } + public override int GetHashCode() { throw null; } + public int GetSignificandBitLength() { throw null; } + public int GetSignificandByteCount() { throw null; } + public System.TypeCode GetTypeCode() { throw null; } + public static System.Numerics.Decimal32 Hypot(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } + public static System.Numerics.Decimal32 Ieee754Remainder(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } + public static int ILogB(System.Numerics.Decimal32 x) { throw null; } + public static bool IsCanonical(System.Numerics.Decimal32 value) { throw null; } + public static bool IsComplexNumber(System.Numerics.Decimal32 value) { throw null; } + public static bool IsEvenInteger(System.Numerics.Decimal32 value) { throw null; } + public static bool IsFinite(System.Numerics.Decimal32 value) { throw null; } + public static bool IsImaginaryNumber(System.Numerics.Decimal32 value) { throw null; } + public static bool IsInfinity(System.Numerics.Decimal32 value) { throw null; } + public static bool IsInteger(System.Numerics.Decimal32 value) { throw null; } + public static bool IsNaN(System.Numerics.Decimal32 value) { throw null; } + public static bool IsNegative(System.Numerics.Decimal32 value) { throw null; } + public static bool IsNegativeInfinity(System.Numerics.Decimal32 value) { throw null; } + public static bool IsNormal(System.Numerics.Decimal32 value) { throw null; } + public static bool IsOddInteger(System.Numerics.Decimal32 value) { throw null; } + public static bool IsPositive(System.Numerics.Decimal32 value) { throw null; } + public static bool IsPositiveInfinity(System.Numerics.Decimal32 value) { throw null; } + public static bool IsRealNumber(System.Numerics.Decimal32 value) { throw null; } + public static bool IsSubnormal(System.Numerics.Decimal32 value) { throw null; } + public static bool IsZero(System.Numerics.Decimal32 value) { throw null; } + public static System.Numerics.Decimal32 Log(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Log(System.Numerics.Decimal32 x, System.Numerics.Decimal32 newBase) { throw null; } + public static System.Numerics.Decimal32 Log10(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Log2(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 MaxMagnitude(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } + public static System.Numerics.Decimal32 MaxMagnitudeNumber(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } + public static System.Numerics.Decimal32 MinMagnitude(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } + public static System.Numerics.Decimal32 MinMagnitudeNumber(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } + public static System.Numerics.Decimal32 operator +(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } + public static System.Numerics.Decimal32 operator --(System.Numerics.Decimal32 value) { throw null; } + public static System.Numerics.Decimal32 operator /(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } + public static bool operator ==(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } + public static bool operator >(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } + public static bool operator >=(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } + public static System.Numerics.Decimal32 operator ++(System.Numerics.Decimal32 value) { throw null; } + public static bool operator !=(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } + public static bool operator <(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } + public static bool operator <=(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } + public static System.Numerics.Decimal32 operator %(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } + public static System.Numerics.Decimal32 operator *(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } + public static System.Numerics.Decimal32 operator -(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } + public static System.Numerics.Decimal32 operator -(System.Numerics.Decimal32 value) { throw null; } + public static System.Numerics.Decimal32 operator +(System.Numerics.Decimal32 value) { throw null; } + public static System.Numerics.Decimal32 Parse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } + public static System.Numerics.Decimal32 Parse(System.ReadOnlySpan s, System.IFormatProvider? provider) { throw null; } + public static System.Numerics.Decimal32 Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } + public static System.Numerics.Decimal32 Parse(string s, System.IFormatProvider? provider) { throw null; } + public static System.Numerics.Decimal32 Pow(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } + public static System.Numerics.Decimal32 Quantize(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } + public static System.Numerics.Decimal32 Quantum(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 RootN(System.Numerics.Decimal32 x, int n) { throw null; } + public static System.Numerics.Decimal32 Round(System.Numerics.Decimal32 x, int digits, System.MidpointRounding mode) { throw null; } + public static bool SameQuantum(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } + public static System.Numerics.Decimal32 ScaleB(System.Numerics.Decimal32 x, int n) { throw null; } + public static System.Numerics.Decimal32 Sin(System.Numerics.Decimal32 x) { throw null; } + public static (System.Numerics.Decimal32 Sin, System.Numerics.Decimal32 Cos) SinCos(System.Numerics.Decimal32 x) { throw null; } + public static (System.Numerics.Decimal32 SinPi, System.Numerics.Decimal32 CosPi) SinCosPi(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Sinh(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 SinPi(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Sqrt(System.Numerics.Decimal32 x) { throw null; } + static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out System.Numerics.Decimal32 result) { throw null; } + static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out System.Numerics.Decimal32 result) { throw null; } + static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out System.Numerics.Decimal32 result) { throw null; } + static bool System.Numerics.INumberBase.TryConvertToChecked(System.Numerics.Decimal32 value, out TOther result) { throw null; } + static bool System.Numerics.INumberBase.TryConvertToSaturating(System.Numerics.Decimal32 value, out TOther result) { throw null; } + static bool System.Numerics.INumberBase.TryConvertToTruncating(System.Numerics.Decimal32 value, out TOther result) { throw null; } + public static System.Numerics.Decimal32 Tan(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Tanh(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 TanPi(System.Numerics.Decimal32 x) { throw null; } + public string ToString(string? format, System.IFormatProvider? formatProvider) { throw null; } + public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format, System.IFormatProvider? provider) { throw null; } + public static bool TryParse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out System.Numerics.Decimal32 result) { throw null; } + public static bool TryParse(System.ReadOnlySpan s, System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out System.Numerics.Decimal32 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out System.Numerics.Decimal32 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out System.Numerics.Decimal32 result) { throw null; } + public bool TryWriteExponentBigEndian(System.Span destination, out int bytesWritten) { throw null; } + public bool TryWriteExponentLittleEndian(System.Span destination, out int bytesWritten) { throw null; } + public bool TryWriteSignificandBigEndian(System.Span destination, out int bytesWritten) { throw null; } + public bool TryWriteSignificandLittleEndian(System.Span destination, out int bytesWritten) { throw null; } + } } diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index 72960086aab846..7ba8971da6585d 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -14,14 +14,17 @@ public readonly struct Decimal32 : IComparable, IComparable, ISpanFormattable, - ISpanParsable, + ISpanParsable, IEquatable, - IConvertible, IDecimalFloatingPointIeee754, IMinMaxValue { private readonly uint _value; + public static Decimal32 MaxValue => throw new NotImplementedException(); + + public static Decimal32 MinValue => throw new NotImplementedException(); + public static Decimal32 Epsilon => throw new NotImplementedException(); public static Decimal32 NaN => throw new NotImplementedException(); @@ -100,10 +103,10 @@ public readonly struct Decimal32 public static Decimal32 MaxMagnitudeNumber(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); public static Decimal32 MinMagnitude(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); public static Decimal32 MinMagnitudeNumber(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); - public static Decimal32 Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider) => throw new NotImplementedException(); - public static Decimal32 Parse(string s, NumberStyles style, IFormatProvider? provider) => throw new NotImplementedException(); public static Decimal32 Parse(ReadOnlySpan s, IFormatProvider? provider) => throw new NotImplementedException(); public static Decimal32 Parse(string s, IFormatProvider? provider) => throw new NotImplementedException(); + public static Decimal32 Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider) => throw new NotImplementedException(); + public static Decimal32 Parse(string s, NumberStyles style, IFormatProvider? provider) => throw new NotImplementedException(); public static Decimal32 Pow(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); public static Decimal32 Quantize(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); public static Decimal32 Quantum(Decimal32 x) => throw new NotImplementedException(); @@ -120,24 +123,24 @@ public readonly struct Decimal32 public static Decimal32 Tan(Decimal32 x) => throw new NotImplementedException(); public static Decimal32 Tanh(Decimal32 x) => throw new NotImplementedException(); public static Decimal32 TanPi(Decimal32 x) => throw new NotImplementedException(); - public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); - public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); + public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); static bool INumberBase.TryConvertFromChecked(TOther value, out Decimal32 result) => throw new NotImplementedException(); static bool INumberBase.TryConvertFromSaturating(TOther value, out Decimal32 result) => throw new NotImplementedException(); static bool INumberBase.TryConvertFromTruncating(TOther value, out Decimal32 result) => throw new NotImplementedException(); static bool INumberBase.TryConvertToChecked(Decimal32 value, out TOther result) => throw new NotImplementedException(); static bool INumberBase.TryConvertToSaturating(Decimal32 value, out TOther result) => throw new NotImplementedException(); static bool INumberBase.TryConvertToTruncating(Decimal32 value, out TOther result) => throw new NotImplementedException(); - public int CompareTo(object? obj) => throw new NotImplementedException(); public int CompareTo(Decimal32 other) => throw new NotImplementedException(); + public int CompareTo(object? obj) => throw new NotImplementedException(); public bool Equals(Decimal32 other) => throw new NotImplementedException(); public int GetExponentByteCount() => throw new NotImplementedException(); public int GetExponentShortestBitLength() => throw new NotImplementedException(); public int GetSignificandBitLength() => throw new NotImplementedException(); public int GetSignificandByteCount() => throw new NotImplementedException(); - public string ToString(string? format, IFormatProvider? formatProvider) => throw new NotImplementedException(); + public TypeCode GetTypeCode() => throw new NotImplementedException(); public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) => throw new NotImplementedException(); public bool TryWriteExponentBigEndian(Span destination, out int bytesWritten) => throw new NotImplementedException(); public bool TryWriteExponentLittleEndian(Span destination, out int bytesWritten) => throw new NotImplementedException(); @@ -159,5 +162,17 @@ public readonly struct Decimal32 public static bool operator >(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); public static bool operator <=(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); public static bool operator >=(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + + public override bool Equals([NotNullWhen(true)] object? obj) + { + return obj is Decimal32 && Equals((Decimal32)obj); + } + + public override int GetHashCode() + { + throw new NotImplementedException(); + } + + public string ToString(string? format, IFormatProvider? formatProvider) => throw new NotImplementedException(); } } diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index c26b436f41097a..592f9a53db7f32 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -10288,6 +10288,12 @@ public partial interface IComparisonOperators : System.N static abstract TResult operator <(TSelf left, TOther right); static abstract TResult operator <=(TSelf left, TOther right); } + public partial interface IDecimalFloatingPointIeee754 : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable, System.IParsable, System.ISpanFormattable, System.ISpanParsable, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity, System.Numerics.IComparisonOperators, System.Numerics.IDecrementOperators, System.Numerics.IDivisionOperators, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions, System.Numerics.IFloatingPoint, System.Numerics.IFloatingPointConstants, System.Numerics.IFloatingPointIeee754, System.Numerics.IHyperbolicFunctions, System.Numerics.IIncrementOperators, System.Numerics.ILogarithmicFunctions, System.Numerics.IModulusOperators, System.Numerics.IMultiplicativeIdentity, System.Numerics.IMultiplyOperators, System.Numerics.INumber, System.Numerics.INumberBase, System.Numerics.IPowerFunctions, System.Numerics.IRootFunctions, System.Numerics.ISignedNumber, System.Numerics.ISubtractionOperators, System.Numerics.ITrigonometricFunctions, System.Numerics.IUnaryNegationOperators, System.Numerics.IUnaryPlusOperators where TSelf : System.Numerics.IDecimalFloatingPointIeee754 + { + static abstract TSelf Quantize(TSelf x, TSelf y); + static abstract TSelf Quantum(TSelf x); + static abstract bool SameQuantum(TSelf x, TSelf y); + } public partial interface IDecrementOperators where TSelf : System.Numerics.IDecrementOperators? { static virtual TSelf operator checked --(TSelf value) { throw null; } From 543bf3d4577680a80ee9c7e6fd959d4a74e513f4 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Wed, 16 Nov 2022 12:14:45 -0600 Subject: [PATCH 03/39] Automatic updates to sln and projitems files --- .../System.Private.CoreLib.sln | 11 +- .../System.Private.CoreLib.Shared.projitems | 7 +- .../src/System.Runtime.Numerics.csproj | 10 +- .../System.Runtime/System.Runtime.sln | 221 +++++++++--------- 4 files changed, 127 insertions(+), 122 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.sln b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.sln index 66c65e680d4693..a0a5851a6ffd71 100644 --- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.sln +++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28902.138 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.32818.431 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib", "System.Private.CoreLib.csproj", "{3DA06C3A-2E7B-4CB7-80ED-9B12916013F9}" EndProject @@ -9,10 +9,6 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib.Generators", "..\..\libraries\System.Private.CoreLib\gen\System.Private.CoreLib.Generators.csproj", "{7196828B-5E00-4BC6-9A1E-492C948E41A3}" EndProject Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - ..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{3da06c3a-2e7b-4cb7-80ed-9b12916013f9}*SharedItemsImports = 5 - ..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{845c8b26-350b-4e63-bd11-2c8150444e28}*SharedItemsImports = 13 - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Checked|amd64 = Checked|amd64 Checked|Any CPU = Checked|Any CPU @@ -95,4 +91,7 @@ Global GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DA05075A-7CDA-4F65-AF6A-CB5DB6CF936F} EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + ..\..\libraries\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{845c8b26-350b-4e63-bd11-2c8150444e28}*SharedItemsImports = 13 + EndGlobalSection EndGlobal diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index b368c8675292c0..c032a8259e687d 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1278,13 +1278,13 @@ Common\System\SR.cs - System\Collections\Concurrent\IProducerConsumerQueue.cs + System\Collections\Concurrent\IProducerConsumerQueue.cs - System\Collections\Concurrent\MultiProducerMultiConsumerQueue.cs + System\Collections\Concurrent\MultiProducerMultiConsumerQueue.cs - System\Collections\Concurrent\SingleProducerSingleConsumerQueue.cs + System\Collections\Concurrent\SingleProducerSingleConsumerQueue.cs Common\System\Collections\Generic\EnumerableHelpers.cs @@ -2479,6 +2479,7 @@ + diff --git a/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj b/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj index 7634a2ce9d800b..23f147615ff226 100644 --- a/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj +++ b/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj @@ -5,6 +5,7 @@ $(NetCoreAppCurrent) + @@ -22,12 +23,9 @@ - - - + + + diff --git a/src/libraries/System.Runtime/System.Runtime.sln b/src/libraries/System.Runtime/System.Runtime.sln index 728d9bfa0e103d..9c4f81e5043a03 100644 --- a/src/libraries/System.Runtime/System.Runtime.sln +++ b/src/libraries/System.Runtime/System.Runtime.sln @@ -1,4 +1,8 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.32818.431 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib", "..\..\coreclr\System.Private.CoreLib\System.Private.CoreLib.csproj", "{71AB8240-F179-4B21-A8BE-8BE6CD774ED9}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities.Unicode", "..\Common\tests\TestUtilities.Unicode\TestUtilities.Unicode.csproj", "{9DF0247E-5B81-4EF3-82CA-3E70B3A56742}" @@ -67,17 +71,23 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{F362E63A-2B1 EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Checked|Any CPU = Checked|Any CPU + Checked|x64 = Checked|x64 + Checked|x86 = Checked|x86 Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 - Checked|Any CPU = Checked|Any CPU - Checked|x64 = Checked|x64 - Checked|x86 = Checked|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Checked|Any CPU.ActiveCfg = Checked|x64 + {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Checked|Any CPU.Build.0 = Checked|x64 + {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Checked|x64.ActiveCfg = Checked|x64 + {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Checked|x64.Build.0 = Checked|x64 + {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Checked|x86.ActiveCfg = Checked|x86 + {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Checked|x86.Build.0 = Checked|x86 {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Debug|Any CPU.ActiveCfg = Debug|x64 {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Debug|Any CPU.Build.0 = Debug|x64 {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Debug|x64.ActiveCfg = Debug|x64 @@ -90,12 +100,9 @@ Global {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Release|x64.Build.0 = Release|x64 {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Release|x86.ActiveCfg = Release|x86 {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Release|x86.Build.0 = Release|x86 - {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Checked|Any CPU.ActiveCfg = Checked|x64 - {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Checked|Any CPU.Build.0 = Checked|x64 - {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Checked|x64.ActiveCfg = Checked|x64 - {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Checked|x64.Build.0 = Checked|x64 - {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Checked|x86.ActiveCfg = Checked|x86 - {71AB8240-F179-4B21-A8BE-8BE6CD774ED9}.Checked|x86.Build.0 = Checked|x86 + {9DF0247E-5B81-4EF3-82CA-3E70B3A56742}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {9DF0247E-5B81-4EF3-82CA-3E70B3A56742}.Checked|x64.ActiveCfg = Debug|Any CPU + {9DF0247E-5B81-4EF3-82CA-3E70B3A56742}.Checked|x86.ActiveCfg = Debug|Any CPU {9DF0247E-5B81-4EF3-82CA-3E70B3A56742}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9DF0247E-5B81-4EF3-82CA-3E70B3A56742}.Debug|Any CPU.Build.0 = Debug|Any CPU {9DF0247E-5B81-4EF3-82CA-3E70B3A56742}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -108,9 +115,9 @@ Global {9DF0247E-5B81-4EF3-82CA-3E70B3A56742}.Release|x64.Build.0 = Release|Any CPU {9DF0247E-5B81-4EF3-82CA-3E70B3A56742}.Release|x86.ActiveCfg = Release|Any CPU {9DF0247E-5B81-4EF3-82CA-3E70B3A56742}.Release|x86.Build.0 = Release|Any CPU - {9DF0247E-5B81-4EF3-82CA-3E70B3A56742}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {9DF0247E-5B81-4EF3-82CA-3E70B3A56742}.Checked|x64.ActiveCfg = Debug|Any CPU - {9DF0247E-5B81-4EF3-82CA-3E70B3A56742}.Checked|x86.ActiveCfg = Debug|Any CPU + {FB17AC52-1633-4845-932B-9218DF895957}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {FB17AC52-1633-4845-932B-9218DF895957}.Checked|x64.ActiveCfg = Debug|Any CPU + {FB17AC52-1633-4845-932B-9218DF895957}.Checked|x86.ActiveCfg = Debug|Any CPU {FB17AC52-1633-4845-932B-9218DF895957}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FB17AC52-1633-4845-932B-9218DF895957}.Debug|Any CPU.Build.0 = Debug|Any CPU {FB17AC52-1633-4845-932B-9218DF895957}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -123,9 +130,9 @@ Global {FB17AC52-1633-4845-932B-9218DF895957}.Release|x64.Build.0 = Release|Any CPU {FB17AC52-1633-4845-932B-9218DF895957}.Release|x86.ActiveCfg = Release|Any CPU {FB17AC52-1633-4845-932B-9218DF895957}.Release|x86.Build.0 = Release|Any CPU - {FB17AC52-1633-4845-932B-9218DF895957}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {FB17AC52-1633-4845-932B-9218DF895957}.Checked|x64.ActiveCfg = Debug|Any CPU - {FB17AC52-1633-4845-932B-9218DF895957}.Checked|x86.ActiveCfg = Debug|Any CPU + {62C2AC8A-7410-4E06-B94E-43BF2DCFBDE9}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {62C2AC8A-7410-4E06-B94E-43BF2DCFBDE9}.Checked|x64.ActiveCfg = Debug|Any CPU + {62C2AC8A-7410-4E06-B94E-43BF2DCFBDE9}.Checked|x86.ActiveCfg = Debug|Any CPU {62C2AC8A-7410-4E06-B94E-43BF2DCFBDE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {62C2AC8A-7410-4E06-B94E-43BF2DCFBDE9}.Debug|Any CPU.Build.0 = Debug|Any CPU {62C2AC8A-7410-4E06-B94E-43BF2DCFBDE9}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -138,9 +145,9 @@ Global {62C2AC8A-7410-4E06-B94E-43BF2DCFBDE9}.Release|x64.Build.0 = Release|Any CPU {62C2AC8A-7410-4E06-B94E-43BF2DCFBDE9}.Release|x86.ActiveCfg = Release|Any CPU {62C2AC8A-7410-4E06-B94E-43BF2DCFBDE9}.Release|x86.Build.0 = Release|Any CPU - {62C2AC8A-7410-4E06-B94E-43BF2DCFBDE9}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {62C2AC8A-7410-4E06-B94E-43BF2DCFBDE9}.Checked|x64.ActiveCfg = Debug|Any CPU - {62C2AC8A-7410-4E06-B94E-43BF2DCFBDE9}.Checked|x86.ActiveCfg = Debug|Any CPU + {B41CB4AB-CDF6-4BB0-B826-D4BAE41411BD}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {B41CB4AB-CDF6-4BB0-B826-D4BAE41411BD}.Checked|x64.ActiveCfg = Debug|Any CPU + {B41CB4AB-CDF6-4BB0-B826-D4BAE41411BD}.Checked|x86.ActiveCfg = Debug|Any CPU {B41CB4AB-CDF6-4BB0-B826-D4BAE41411BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B41CB4AB-CDF6-4BB0-B826-D4BAE41411BD}.Debug|Any CPU.Build.0 = Debug|Any CPU {B41CB4AB-CDF6-4BB0-B826-D4BAE41411BD}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -153,9 +160,9 @@ Global {B41CB4AB-CDF6-4BB0-B826-D4BAE41411BD}.Release|x64.Build.0 = Release|Any CPU {B41CB4AB-CDF6-4BB0-B826-D4BAE41411BD}.Release|x86.ActiveCfg = Release|Any CPU {B41CB4AB-CDF6-4BB0-B826-D4BAE41411BD}.Release|x86.Build.0 = Release|Any CPU - {B41CB4AB-CDF6-4BB0-B826-D4BAE41411BD}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {B41CB4AB-CDF6-4BB0-B826-D4BAE41411BD}.Checked|x64.ActiveCfg = Debug|Any CPU - {B41CB4AB-CDF6-4BB0-B826-D4BAE41411BD}.Checked|x86.ActiveCfg = Debug|Any CPU + {9C41B325-1225-43CA-9436-549AFF6D90A1}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {9C41B325-1225-43CA-9436-549AFF6D90A1}.Checked|x64.ActiveCfg = Debug|Any CPU + {9C41B325-1225-43CA-9436-549AFF6D90A1}.Checked|x86.ActiveCfg = Debug|Any CPU {9C41B325-1225-43CA-9436-549AFF6D90A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9C41B325-1225-43CA-9436-549AFF6D90A1}.Debug|Any CPU.Build.0 = Debug|Any CPU {9C41B325-1225-43CA-9436-549AFF6D90A1}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -168,9 +175,9 @@ Global {9C41B325-1225-43CA-9436-549AFF6D90A1}.Release|x64.Build.0 = Release|Any CPU {9C41B325-1225-43CA-9436-549AFF6D90A1}.Release|x86.ActiveCfg = Release|Any CPU {9C41B325-1225-43CA-9436-549AFF6D90A1}.Release|x86.Build.0 = Release|Any CPU - {9C41B325-1225-43CA-9436-549AFF6D90A1}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {9C41B325-1225-43CA-9436-549AFF6D90A1}.Checked|x64.ActiveCfg = Debug|Any CPU - {9C41B325-1225-43CA-9436-549AFF6D90A1}.Checked|x86.ActiveCfg = Debug|Any CPU + {F27DC16B-64F4-4BD7-AF9C-1C76F7ACC88B}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {F27DC16B-64F4-4BD7-AF9C-1C76F7ACC88B}.Checked|x64.ActiveCfg = Debug|Any CPU + {F27DC16B-64F4-4BD7-AF9C-1C76F7ACC88B}.Checked|x86.ActiveCfg = Debug|Any CPU {F27DC16B-64F4-4BD7-AF9C-1C76F7ACC88B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F27DC16B-64F4-4BD7-AF9C-1C76F7ACC88B}.Debug|Any CPU.Build.0 = Debug|Any CPU {F27DC16B-64F4-4BD7-AF9C-1C76F7ACC88B}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -183,9 +190,9 @@ Global {F27DC16B-64F4-4BD7-AF9C-1C76F7ACC88B}.Release|x64.Build.0 = Release|Any CPU {F27DC16B-64F4-4BD7-AF9C-1C76F7ACC88B}.Release|x86.ActiveCfg = Release|Any CPU {F27DC16B-64F4-4BD7-AF9C-1C76F7ACC88B}.Release|x86.Build.0 = Release|Any CPU - {F27DC16B-64F4-4BD7-AF9C-1C76F7ACC88B}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {F27DC16B-64F4-4BD7-AF9C-1C76F7ACC88B}.Checked|x64.ActiveCfg = Debug|Any CPU - {F27DC16B-64F4-4BD7-AF9C-1C76F7ACC88B}.Checked|x86.ActiveCfg = Debug|Any CPU + {CF79B5AE-38CB-4B80-BF92-CF634C0B7EC3}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {CF79B5AE-38CB-4B80-BF92-CF634C0B7EC3}.Checked|x64.ActiveCfg = Debug|Any CPU + {CF79B5AE-38CB-4B80-BF92-CF634C0B7EC3}.Checked|x86.ActiveCfg = Debug|Any CPU {CF79B5AE-38CB-4B80-BF92-CF634C0B7EC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CF79B5AE-38CB-4B80-BF92-CF634C0B7EC3}.Debug|Any CPU.Build.0 = Debug|Any CPU {CF79B5AE-38CB-4B80-BF92-CF634C0B7EC3}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -198,9 +205,9 @@ Global {CF79B5AE-38CB-4B80-BF92-CF634C0B7EC3}.Release|x64.Build.0 = Release|Any CPU {CF79B5AE-38CB-4B80-BF92-CF634C0B7EC3}.Release|x86.ActiveCfg = Release|Any CPU {CF79B5AE-38CB-4B80-BF92-CF634C0B7EC3}.Release|x86.Build.0 = Release|Any CPU - {CF79B5AE-38CB-4B80-BF92-CF634C0B7EC3}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {CF79B5AE-38CB-4B80-BF92-CF634C0B7EC3}.Checked|x64.ActiveCfg = Debug|Any CPU - {CF79B5AE-38CB-4B80-BF92-CF634C0B7EC3}.Checked|x86.ActiveCfg = Debug|Any CPU + {E64D31D0-8F38-4FDF-B60D-F955D2475566}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {E64D31D0-8F38-4FDF-B60D-F955D2475566}.Checked|x64.ActiveCfg = Debug|Any CPU + {E64D31D0-8F38-4FDF-B60D-F955D2475566}.Checked|x86.ActiveCfg = Debug|Any CPU {E64D31D0-8F38-4FDF-B60D-F955D2475566}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E64D31D0-8F38-4FDF-B60D-F955D2475566}.Debug|Any CPU.Build.0 = Debug|Any CPU {E64D31D0-8F38-4FDF-B60D-F955D2475566}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -213,9 +220,9 @@ Global {E64D31D0-8F38-4FDF-B60D-F955D2475566}.Release|x64.Build.0 = Release|Any CPU {E64D31D0-8F38-4FDF-B60D-F955D2475566}.Release|x86.ActiveCfg = Release|Any CPU {E64D31D0-8F38-4FDF-B60D-F955D2475566}.Release|x86.Build.0 = Release|Any CPU - {E64D31D0-8F38-4FDF-B60D-F955D2475566}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {E64D31D0-8F38-4FDF-B60D-F955D2475566}.Checked|x64.ActiveCfg = Debug|Any CPU - {E64D31D0-8F38-4FDF-B60D-F955D2475566}.Checked|x86.ActiveCfg = Debug|Any CPU + {E7A05515-DABE-4C09-83CB-CE84EFDCD4CC}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {E7A05515-DABE-4C09-83CB-CE84EFDCD4CC}.Checked|x64.ActiveCfg = Debug|Any CPU + {E7A05515-DABE-4C09-83CB-CE84EFDCD4CC}.Checked|x86.ActiveCfg = Debug|Any CPU {E7A05515-DABE-4C09-83CB-CE84EFDCD4CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E7A05515-DABE-4C09-83CB-CE84EFDCD4CC}.Debug|Any CPU.Build.0 = Debug|Any CPU {E7A05515-DABE-4C09-83CB-CE84EFDCD4CC}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -228,9 +235,9 @@ Global {E7A05515-DABE-4C09-83CB-CE84EFDCD4CC}.Release|x64.Build.0 = Release|Any CPU {E7A05515-DABE-4C09-83CB-CE84EFDCD4CC}.Release|x86.ActiveCfg = Release|Any CPU {E7A05515-DABE-4C09-83CB-CE84EFDCD4CC}.Release|x86.Build.0 = Release|Any CPU - {E7A05515-DABE-4C09-83CB-CE84EFDCD4CC}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {E7A05515-DABE-4C09-83CB-CE84EFDCD4CC}.Checked|x64.ActiveCfg = Debug|Any CPU - {E7A05515-DABE-4C09-83CB-CE84EFDCD4CC}.Checked|x86.ActiveCfg = Debug|Any CPU + {4FA4A9A6-1D38-414B-96F0-3CFB63C687C9}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {4FA4A9A6-1D38-414B-96F0-3CFB63C687C9}.Checked|x64.ActiveCfg = Debug|Any CPU + {4FA4A9A6-1D38-414B-96F0-3CFB63C687C9}.Checked|x86.ActiveCfg = Debug|Any CPU {4FA4A9A6-1D38-414B-96F0-3CFB63C687C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4FA4A9A6-1D38-414B-96F0-3CFB63C687C9}.Debug|Any CPU.Build.0 = Debug|Any CPU {4FA4A9A6-1D38-414B-96F0-3CFB63C687C9}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -243,9 +250,9 @@ Global {4FA4A9A6-1D38-414B-96F0-3CFB63C687C9}.Release|x64.Build.0 = Release|Any CPU {4FA4A9A6-1D38-414B-96F0-3CFB63C687C9}.Release|x86.ActiveCfg = Release|Any CPU {4FA4A9A6-1D38-414B-96F0-3CFB63C687C9}.Release|x86.Build.0 = Release|Any CPU - {4FA4A9A6-1D38-414B-96F0-3CFB63C687C9}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {4FA4A9A6-1D38-414B-96F0-3CFB63C687C9}.Checked|x64.ActiveCfg = Debug|Any CPU - {4FA4A9A6-1D38-414B-96F0-3CFB63C687C9}.Checked|x86.ActiveCfg = Debug|Any CPU + {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37}.Checked|x64.ActiveCfg = Debug|Any CPU + {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37}.Checked|x86.ActiveCfg = Debug|Any CPU {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37}.Debug|Any CPU.Build.0 = Debug|Any CPU {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -258,9 +265,9 @@ Global {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37}.Release|x64.Build.0 = Release|Any CPU {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37}.Release|x86.ActiveCfg = Release|Any CPU {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37}.Release|x86.Build.0 = Release|Any CPU - {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37}.Checked|x64.ActiveCfg = Debug|Any CPU - {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37}.Checked|x86.ActiveCfg = Debug|Any CPU + {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C}.Checked|x64.ActiveCfg = Debug|Any CPU + {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C}.Checked|x86.ActiveCfg = Debug|Any CPU {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C}.Debug|Any CPU.Build.0 = Debug|Any CPU {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -273,9 +280,9 @@ Global {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C}.Release|x64.Build.0 = Release|Any CPU {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C}.Release|x86.ActiveCfg = Release|Any CPU {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C}.Release|x86.Build.0 = Release|Any CPU - {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C}.Checked|x64.ActiveCfg = Debug|Any CPU - {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C}.Checked|x86.ActiveCfg = Debug|Any CPU + {A83A8520-F5E2-49B4-83BC-0F82A412951D}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {A83A8520-F5E2-49B4-83BC-0F82A412951D}.Checked|x64.ActiveCfg = Debug|Any CPU + {A83A8520-F5E2-49B4-83BC-0F82A412951D}.Checked|x86.ActiveCfg = Debug|Any CPU {A83A8520-F5E2-49B4-83BC-0F82A412951D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A83A8520-F5E2-49B4-83BC-0F82A412951D}.Debug|Any CPU.Build.0 = Debug|Any CPU {A83A8520-F5E2-49B4-83BC-0F82A412951D}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -288,9 +295,9 @@ Global {A83A8520-F5E2-49B4-83BC-0F82A412951D}.Release|x64.Build.0 = Release|Any CPU {A83A8520-F5E2-49B4-83BC-0F82A412951D}.Release|x86.ActiveCfg = Release|Any CPU {A83A8520-F5E2-49B4-83BC-0F82A412951D}.Release|x86.Build.0 = Release|Any CPU - {A83A8520-F5E2-49B4-83BC-0F82A412951D}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {A83A8520-F5E2-49B4-83BC-0F82A412951D}.Checked|x64.ActiveCfg = Debug|Any CPU - {A83A8520-F5E2-49B4-83BC-0F82A412951D}.Checked|x86.ActiveCfg = Debug|Any CPU + {3B79DD71-8C2F-41BC-A1A7-86A490D6C726}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {3B79DD71-8C2F-41BC-A1A7-86A490D6C726}.Checked|x64.ActiveCfg = Debug|Any CPU + {3B79DD71-8C2F-41BC-A1A7-86A490D6C726}.Checked|x86.ActiveCfg = Debug|Any CPU {3B79DD71-8C2F-41BC-A1A7-86A490D6C726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3B79DD71-8C2F-41BC-A1A7-86A490D6C726}.Debug|Any CPU.Build.0 = Debug|Any CPU {3B79DD71-8C2F-41BC-A1A7-86A490D6C726}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -303,9 +310,9 @@ Global {3B79DD71-8C2F-41BC-A1A7-86A490D6C726}.Release|x64.Build.0 = Release|Any CPU {3B79DD71-8C2F-41BC-A1A7-86A490D6C726}.Release|x86.ActiveCfg = Release|Any CPU {3B79DD71-8C2F-41BC-A1A7-86A490D6C726}.Release|x86.Build.0 = Release|Any CPU - {3B79DD71-8C2F-41BC-A1A7-86A490D6C726}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {3B79DD71-8C2F-41BC-A1A7-86A490D6C726}.Checked|x64.ActiveCfg = Debug|Any CPU - {3B79DD71-8C2F-41BC-A1A7-86A490D6C726}.Checked|x86.ActiveCfg = Debug|Any CPU + {4EE36055-AD7C-4779-B3F6-08687960DCC3}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {4EE36055-AD7C-4779-B3F6-08687960DCC3}.Checked|x64.ActiveCfg = Debug|Any CPU + {4EE36055-AD7C-4779-B3F6-08687960DCC3}.Checked|x86.ActiveCfg = Debug|Any CPU {4EE36055-AD7C-4779-B3F6-08687960DCC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4EE36055-AD7C-4779-B3F6-08687960DCC3}.Debug|Any CPU.Build.0 = Debug|Any CPU {4EE36055-AD7C-4779-B3F6-08687960DCC3}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -318,9 +325,9 @@ Global {4EE36055-AD7C-4779-B3F6-08687960DCC3}.Release|x64.Build.0 = Release|Any CPU {4EE36055-AD7C-4779-B3F6-08687960DCC3}.Release|x86.ActiveCfg = Release|Any CPU {4EE36055-AD7C-4779-B3F6-08687960DCC3}.Release|x86.Build.0 = Release|Any CPU - {4EE36055-AD7C-4779-B3F6-08687960DCC3}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {4EE36055-AD7C-4779-B3F6-08687960DCC3}.Checked|x64.ActiveCfg = Debug|Any CPU - {4EE36055-AD7C-4779-B3F6-08687960DCC3}.Checked|x86.ActiveCfg = Debug|Any CPU + {C3F25EEF-04B4-407A-960B-0C1CE9C04430}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {C3F25EEF-04B4-407A-960B-0C1CE9C04430}.Checked|x64.ActiveCfg = Debug|Any CPU + {C3F25EEF-04B4-407A-960B-0C1CE9C04430}.Checked|x86.ActiveCfg = Debug|Any CPU {C3F25EEF-04B4-407A-960B-0C1CE9C04430}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C3F25EEF-04B4-407A-960B-0C1CE9C04430}.Debug|Any CPU.Build.0 = Debug|Any CPU {C3F25EEF-04B4-407A-960B-0C1CE9C04430}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -333,9 +340,9 @@ Global {C3F25EEF-04B4-407A-960B-0C1CE9C04430}.Release|x64.Build.0 = Release|Any CPU {C3F25EEF-04B4-407A-960B-0C1CE9C04430}.Release|x86.ActiveCfg = Release|Any CPU {C3F25EEF-04B4-407A-960B-0C1CE9C04430}.Release|x86.Build.0 = Release|Any CPU - {C3F25EEF-04B4-407A-960B-0C1CE9C04430}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {C3F25EEF-04B4-407A-960B-0C1CE9C04430}.Checked|x64.ActiveCfg = Debug|Any CPU - {C3F25EEF-04B4-407A-960B-0C1CE9C04430}.Checked|x86.ActiveCfg = Debug|Any CPU + {47E26787-7C27-4572-AD8B-868DE44E2C48}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {47E26787-7C27-4572-AD8B-868DE44E2C48}.Checked|x64.ActiveCfg = Debug|Any CPU + {47E26787-7C27-4572-AD8B-868DE44E2C48}.Checked|x86.ActiveCfg = Debug|Any CPU {47E26787-7C27-4572-AD8B-868DE44E2C48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {47E26787-7C27-4572-AD8B-868DE44E2C48}.Debug|Any CPU.Build.0 = Debug|Any CPU {47E26787-7C27-4572-AD8B-868DE44E2C48}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -348,9 +355,9 @@ Global {47E26787-7C27-4572-AD8B-868DE44E2C48}.Release|x64.Build.0 = Release|Any CPU {47E26787-7C27-4572-AD8B-868DE44E2C48}.Release|x86.ActiveCfg = Release|Any CPU {47E26787-7C27-4572-AD8B-868DE44E2C48}.Release|x86.Build.0 = Release|Any CPU - {47E26787-7C27-4572-AD8B-868DE44E2C48}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {47E26787-7C27-4572-AD8B-868DE44E2C48}.Checked|x64.ActiveCfg = Debug|Any CPU - {47E26787-7C27-4572-AD8B-868DE44E2C48}.Checked|x86.ActiveCfg = Debug|Any CPU + {C230AC88-A377-4BEB-824F-AB174C14DC86}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {C230AC88-A377-4BEB-824F-AB174C14DC86}.Checked|x64.ActiveCfg = Debug|Any CPU + {C230AC88-A377-4BEB-824F-AB174C14DC86}.Checked|x86.ActiveCfg = Debug|Any CPU {C230AC88-A377-4BEB-824F-AB174C14DC86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C230AC88-A377-4BEB-824F-AB174C14DC86}.Debug|Any CPU.Build.0 = Debug|Any CPU {C230AC88-A377-4BEB-824F-AB174C14DC86}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -363,9 +370,9 @@ Global {C230AC88-A377-4BEB-824F-AB174C14DC86}.Release|x64.Build.0 = Release|Any CPU {C230AC88-A377-4BEB-824F-AB174C14DC86}.Release|x86.ActiveCfg = Release|Any CPU {C230AC88-A377-4BEB-824F-AB174C14DC86}.Release|x86.Build.0 = Release|Any CPU - {C230AC88-A377-4BEB-824F-AB174C14DC86}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {C230AC88-A377-4BEB-824F-AB174C14DC86}.Checked|x64.ActiveCfg = Debug|Any CPU - {C230AC88-A377-4BEB-824F-AB174C14DC86}.Checked|x86.ActiveCfg = Debug|Any CPU + {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Checked|x64.ActiveCfg = Debug|Any CPU + {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Checked|x86.ActiveCfg = Debug|Any CPU {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Debug|Any CPU.Build.0 = Debug|Any CPU {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -378,9 +385,9 @@ Global {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Release|x64.Build.0 = Release|Any CPU {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Release|x86.ActiveCfg = Release|Any CPU {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Release|x86.Build.0 = Release|Any CPU - {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Checked|x64.ActiveCfg = Debug|Any CPU - {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC}.Checked|x86.ActiveCfg = Debug|Any CPU + {0F83B07B-2E3F-4708-BE6D-7A8DA8168803}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {0F83B07B-2E3F-4708-BE6D-7A8DA8168803}.Checked|x64.ActiveCfg = Debug|Any CPU + {0F83B07B-2E3F-4708-BE6D-7A8DA8168803}.Checked|x86.ActiveCfg = Debug|Any CPU {0F83B07B-2E3F-4708-BE6D-7A8DA8168803}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0F83B07B-2E3F-4708-BE6D-7A8DA8168803}.Debug|Any CPU.Build.0 = Debug|Any CPU {0F83B07B-2E3F-4708-BE6D-7A8DA8168803}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -393,9 +400,9 @@ Global {0F83B07B-2E3F-4708-BE6D-7A8DA8168803}.Release|x64.Build.0 = Release|Any CPU {0F83B07B-2E3F-4708-BE6D-7A8DA8168803}.Release|x86.ActiveCfg = Release|Any CPU {0F83B07B-2E3F-4708-BE6D-7A8DA8168803}.Release|x86.Build.0 = Release|Any CPU - {0F83B07B-2E3F-4708-BE6D-7A8DA8168803}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {0F83B07B-2E3F-4708-BE6D-7A8DA8168803}.Checked|x64.ActiveCfg = Debug|Any CPU - {0F83B07B-2E3F-4708-BE6D-7A8DA8168803}.Checked|x86.ActiveCfg = Debug|Any CPU + {833C1D45-9BBB-4A92-93B7-4EFFD9E945AD}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {833C1D45-9BBB-4A92-93B7-4EFFD9E945AD}.Checked|x64.ActiveCfg = Debug|Any CPU + {833C1D45-9BBB-4A92-93B7-4EFFD9E945AD}.Checked|x86.ActiveCfg = Debug|Any CPU {833C1D45-9BBB-4A92-93B7-4EFFD9E945AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {833C1D45-9BBB-4A92-93B7-4EFFD9E945AD}.Debug|Any CPU.Build.0 = Debug|Any CPU {833C1D45-9BBB-4A92-93B7-4EFFD9E945AD}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -408,9 +415,9 @@ Global {833C1D45-9BBB-4A92-93B7-4EFFD9E945AD}.Release|x64.Build.0 = Release|Any CPU {833C1D45-9BBB-4A92-93B7-4EFFD9E945AD}.Release|x86.ActiveCfg = Release|Any CPU {833C1D45-9BBB-4A92-93B7-4EFFD9E945AD}.Release|x86.Build.0 = Release|Any CPU - {833C1D45-9BBB-4A92-93B7-4EFFD9E945AD}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {833C1D45-9BBB-4A92-93B7-4EFFD9E945AD}.Checked|x64.ActiveCfg = Debug|Any CPU - {833C1D45-9BBB-4A92-93B7-4EFFD9E945AD}.Checked|x86.ActiveCfg = Debug|Any CPU + {1B4552A4-91FD-4C6F-9EB4-3454C4BE428F}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {1B4552A4-91FD-4C6F-9EB4-3454C4BE428F}.Checked|x64.ActiveCfg = Debug|Any CPU + {1B4552A4-91FD-4C6F-9EB4-3454C4BE428F}.Checked|x86.ActiveCfg = Debug|Any CPU {1B4552A4-91FD-4C6F-9EB4-3454C4BE428F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1B4552A4-91FD-4C6F-9EB4-3454C4BE428F}.Debug|Any CPU.Build.0 = Debug|Any CPU {1B4552A4-91FD-4C6F-9EB4-3454C4BE428F}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -423,9 +430,9 @@ Global {1B4552A4-91FD-4C6F-9EB4-3454C4BE428F}.Release|x64.Build.0 = Release|Any CPU {1B4552A4-91FD-4C6F-9EB4-3454C4BE428F}.Release|x86.ActiveCfg = Release|Any CPU {1B4552A4-91FD-4C6F-9EB4-3454C4BE428F}.Release|x86.Build.0 = Release|Any CPU - {1B4552A4-91FD-4C6F-9EB4-3454C4BE428F}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {1B4552A4-91FD-4C6F-9EB4-3454C4BE428F}.Checked|x64.ActiveCfg = Debug|Any CPU - {1B4552A4-91FD-4C6F-9EB4-3454C4BE428F}.Checked|x86.ActiveCfg = Debug|Any CPU + {F6A8185B-07C6-401D-9B40-3C560239E05F}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {F6A8185B-07C6-401D-9B40-3C560239E05F}.Checked|x64.ActiveCfg = Debug|Any CPU + {F6A8185B-07C6-401D-9B40-3C560239E05F}.Checked|x86.ActiveCfg = Debug|Any CPU {F6A8185B-07C6-401D-9B40-3C560239E05F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F6A8185B-07C6-401D-9B40-3C560239E05F}.Debug|Any CPU.Build.0 = Debug|Any CPU {F6A8185B-07C6-401D-9B40-3C560239E05F}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -438,9 +445,9 @@ Global {F6A8185B-07C6-401D-9B40-3C560239E05F}.Release|x64.Build.0 = Release|Any CPU {F6A8185B-07C6-401D-9B40-3C560239E05F}.Release|x86.ActiveCfg = Release|Any CPU {F6A8185B-07C6-401D-9B40-3C560239E05F}.Release|x86.Build.0 = Release|Any CPU - {F6A8185B-07C6-401D-9B40-3C560239E05F}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {F6A8185B-07C6-401D-9B40-3C560239E05F}.Checked|x64.ActiveCfg = Debug|Any CPU - {F6A8185B-07C6-401D-9B40-3C560239E05F}.Checked|x86.ActiveCfg = Debug|Any CPU + {EC777939-BE30-4ED9-9FE1-451DD7472467}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {EC777939-BE30-4ED9-9FE1-451DD7472467}.Checked|x64.ActiveCfg = Debug|Any CPU + {EC777939-BE30-4ED9-9FE1-451DD7472467}.Checked|x86.ActiveCfg = Debug|Any CPU {EC777939-BE30-4ED9-9FE1-451DD7472467}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EC777939-BE30-4ED9-9FE1-451DD7472467}.Debug|Any CPU.Build.0 = Debug|Any CPU {EC777939-BE30-4ED9-9FE1-451DD7472467}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -453,9 +460,9 @@ Global {EC777939-BE30-4ED9-9FE1-451DD7472467}.Release|x64.Build.0 = Release|Any CPU {EC777939-BE30-4ED9-9FE1-451DD7472467}.Release|x86.ActiveCfg = Release|Any CPU {EC777939-BE30-4ED9-9FE1-451DD7472467}.Release|x86.Build.0 = Release|Any CPU - {EC777939-BE30-4ED9-9FE1-451DD7472467}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {EC777939-BE30-4ED9-9FE1-451DD7472467}.Checked|x64.ActiveCfg = Debug|Any CPU - {EC777939-BE30-4ED9-9FE1-451DD7472467}.Checked|x86.ActiveCfg = Debug|Any CPU + {25E8AB9D-2D10-44F5-9F83-5A5134526771}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {25E8AB9D-2D10-44F5-9F83-5A5134526771}.Checked|x64.ActiveCfg = Debug|Any CPU + {25E8AB9D-2D10-44F5-9F83-5A5134526771}.Checked|x86.ActiveCfg = Debug|Any CPU {25E8AB9D-2D10-44F5-9F83-5A5134526771}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {25E8AB9D-2D10-44F5-9F83-5A5134526771}.Debug|Any CPU.Build.0 = Debug|Any CPU {25E8AB9D-2D10-44F5-9F83-5A5134526771}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -468,9 +475,9 @@ Global {25E8AB9D-2D10-44F5-9F83-5A5134526771}.Release|x64.Build.0 = Release|Any CPU {25E8AB9D-2D10-44F5-9F83-5A5134526771}.Release|x86.ActiveCfg = Release|Any CPU {25E8AB9D-2D10-44F5-9F83-5A5134526771}.Release|x86.Build.0 = Release|Any CPU - {25E8AB9D-2D10-44F5-9F83-5A5134526771}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {25E8AB9D-2D10-44F5-9F83-5A5134526771}.Checked|x64.ActiveCfg = Debug|Any CPU - {25E8AB9D-2D10-44F5-9F83-5A5134526771}.Checked|x86.ActiveCfg = Debug|Any CPU + {9CF6C6E6-0E9F-4A95-84B5-6083EAB6FA13}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {9CF6C6E6-0E9F-4A95-84B5-6083EAB6FA13}.Checked|x64.ActiveCfg = Debug|Any CPU + {9CF6C6E6-0E9F-4A95-84B5-6083EAB6FA13}.Checked|x86.ActiveCfg = Debug|Any CPU {9CF6C6E6-0E9F-4A95-84B5-6083EAB6FA13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9CF6C6E6-0E9F-4A95-84B5-6083EAB6FA13}.Debug|Any CPU.Build.0 = Debug|Any CPU {9CF6C6E6-0E9F-4A95-84B5-6083EAB6FA13}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -483,9 +490,9 @@ Global {9CF6C6E6-0E9F-4A95-84B5-6083EAB6FA13}.Release|x64.Build.0 = Release|Any CPU {9CF6C6E6-0E9F-4A95-84B5-6083EAB6FA13}.Release|x86.ActiveCfg = Release|Any CPU {9CF6C6E6-0E9F-4A95-84B5-6083EAB6FA13}.Release|x86.Build.0 = Release|Any CPU - {9CF6C6E6-0E9F-4A95-84B5-6083EAB6FA13}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {9CF6C6E6-0E9F-4A95-84B5-6083EAB6FA13}.Checked|x64.ActiveCfg = Debug|Any CPU - {9CF6C6E6-0E9F-4A95-84B5-6083EAB6FA13}.Checked|x86.ActiveCfg = Debug|Any CPU + {82728202-1098-4E16-B598-5762EAF67D08}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {82728202-1098-4E16-B598-5762EAF67D08}.Checked|x64.ActiveCfg = Debug|Any CPU + {82728202-1098-4E16-B598-5762EAF67D08}.Checked|x86.ActiveCfg = Debug|Any CPU {82728202-1098-4E16-B598-5762EAF67D08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {82728202-1098-4E16-B598-5762EAF67D08}.Debug|Any CPU.Build.0 = Debug|Any CPU {82728202-1098-4E16-B598-5762EAF67D08}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -498,9 +505,9 @@ Global {82728202-1098-4E16-B598-5762EAF67D08}.Release|x64.Build.0 = Release|Any CPU {82728202-1098-4E16-B598-5762EAF67D08}.Release|x86.ActiveCfg = Release|Any CPU {82728202-1098-4E16-B598-5762EAF67D08}.Release|x86.Build.0 = Release|Any CPU - {82728202-1098-4E16-B598-5762EAF67D08}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {82728202-1098-4E16-B598-5762EAF67D08}.Checked|x64.ActiveCfg = Debug|Any CPU - {82728202-1098-4E16-B598-5762EAF67D08}.Checked|x86.ActiveCfg = Debug|Any CPU + {069C2B51-069A-4FBB-BFE9-42D573F1CEEA}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {069C2B51-069A-4FBB-BFE9-42D573F1CEEA}.Checked|x64.ActiveCfg = Debug|Any CPU + {069C2B51-069A-4FBB-BFE9-42D573F1CEEA}.Checked|x86.ActiveCfg = Debug|Any CPU {069C2B51-069A-4FBB-BFE9-42D573F1CEEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {069C2B51-069A-4FBB-BFE9-42D573F1CEEA}.Debug|Any CPU.Build.0 = Debug|Any CPU {069C2B51-069A-4FBB-BFE9-42D573F1CEEA}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -513,24 +520,25 @@ Global {069C2B51-069A-4FBB-BFE9-42D573F1CEEA}.Release|x64.Build.0 = Release|Any CPU {069C2B51-069A-4FBB-BFE9-42D573F1CEEA}.Release|x86.ActiveCfg = Release|Any CPU {069C2B51-069A-4FBB-BFE9-42D573F1CEEA}.Release|x86.Build.0 = Release|Any CPU - {069C2B51-069A-4FBB-BFE9-42D573F1CEEA}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {069C2B51-069A-4FBB-BFE9-42D573F1CEEA}.Checked|x64.ActiveCfg = Debug|Any CPU - {069C2B51-069A-4FBB-BFE9-42D573F1CEEA}.Checked|x86.ActiveCfg = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {71AB8240-F179-4B21-A8BE-8BE6CD774ED9} = {28140562-A65A-48E9-ABAB-53BA939084F0} + {9DF0247E-5B81-4EF3-82CA-3E70B3A56742} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} + {FB17AC52-1633-4845-932B-9218DF895957} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} + {62C2AC8A-7410-4E06-B94E-43BF2DCFBDE9} = {5B2B5E7E-A2FB-4095-9E79-404BF53E0133} {B41CB4AB-CDF6-4BB0-B826-D4BAE41411BD} = {28140562-A65A-48E9-ABAB-53BA939084F0} + {9C41B325-1225-43CA-9436-549AFF6D90A1} = {5B2B5E7E-A2FB-4095-9E79-404BF53E0133} {F27DC16B-64F4-4BD7-AF9C-1C76F7ACC88B} = {28140562-A65A-48E9-ABAB-53BA939084F0} + {CF79B5AE-38CB-4B80-BF92-CF634C0B7EC3} = {F362E63A-2B1A-445B-B198-3071D7DDE8CF} + {E64D31D0-8F38-4FDF-B60D-F955D2475566} = {5B2B5E7E-A2FB-4095-9E79-404BF53E0133} {E7A05515-DABE-4C09-83CB-CE84EFDCD4CC} = {28140562-A65A-48E9-ABAB-53BA939084F0} + {4FA4A9A6-1D38-414B-96F0-3CFB63C687C9} = {F362E63A-2B1A-445B-B198-3071D7DDE8CF} + {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37} = {F362E63A-2B1A-445B-B198-3071D7DDE8CF} + {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C} = {5B2B5E7E-A2FB-4095-9E79-404BF53E0133} {A83A8520-F5E2-49B4-83BC-0F82A412951D} = {28140562-A65A-48E9-ABAB-53BA939084F0} - {F6A8185B-07C6-401D-9B40-3C560239E05F} = {28140562-A65A-48E9-ABAB-53BA939084F0} - {9CF6C6E6-0E9F-4A95-84B5-6083EAB6FA13} = {28140562-A65A-48E9-ABAB-53BA939084F0} - {069C2B51-069A-4FBB-BFE9-42D573F1CEEA} = {28140562-A65A-48E9-ABAB-53BA939084F0} - {9DF0247E-5B81-4EF3-82CA-3E70B3A56742} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} - {FB17AC52-1633-4845-932B-9218DF895957} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {3B79DD71-8C2F-41BC-A1A7-86A490D6C726} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {4EE36055-AD7C-4779-B3F6-08687960DCC3} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {C3F25EEF-04B4-407A-960B-0C1CE9C04430} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} @@ -539,19 +547,18 @@ Global {1BCCD2F5-A561-4641-8A0B-51F3EDCA35DC} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {0F83B07B-2E3F-4708-BE6D-7A8DA8168803} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} {833C1D45-9BBB-4A92-93B7-4EFFD9E945AD} = {FD72C125-C10D-457B-8AFC-6B4E5237AF6A} - {62C2AC8A-7410-4E06-B94E-43BF2DCFBDE9} = {5B2B5E7E-A2FB-4095-9E79-404BF53E0133} - {9C41B325-1225-43CA-9436-549AFF6D90A1} = {5B2B5E7E-A2FB-4095-9E79-404BF53E0133} - {E64D31D0-8F38-4FDF-B60D-F955D2475566} = {5B2B5E7E-A2FB-4095-9E79-404BF53E0133} - {F39E2C7E-5FE1-460C-AC2C-7E2B50955F2C} = {5B2B5E7E-A2FB-4095-9E79-404BF53E0133} {1B4552A4-91FD-4C6F-9EB4-3454C4BE428F} = {5B2B5E7E-A2FB-4095-9E79-404BF53E0133} + {F6A8185B-07C6-401D-9B40-3C560239E05F} = {28140562-A65A-48E9-ABAB-53BA939084F0} + {EC777939-BE30-4ED9-9FE1-451DD7472467} = {F362E63A-2B1A-445B-B198-3071D7DDE8CF} {25E8AB9D-2D10-44F5-9F83-5A5134526771} = {5B2B5E7E-A2FB-4095-9E79-404BF53E0133} + {9CF6C6E6-0E9F-4A95-84B5-6083EAB6FA13} = {28140562-A65A-48E9-ABAB-53BA939084F0} {82728202-1098-4E16-B598-5762EAF67D08} = {5B2B5E7E-A2FB-4095-9E79-404BF53E0133} - {CF79B5AE-38CB-4B80-BF92-CF634C0B7EC3} = {F362E63A-2B1A-445B-B198-3071D7DDE8CF} - {4FA4A9A6-1D38-414B-96F0-3CFB63C687C9} = {F362E63A-2B1A-445B-B198-3071D7DDE8CF} - {A7B7DE04-7261-4D4C-AA78-9F2D9B5A1C37} = {F362E63A-2B1A-445B-B198-3071D7DDE8CF} - {EC777939-BE30-4ED9-9FE1-451DD7472467} = {F362E63A-2B1A-445B-B198-3071D7DDE8CF} + {069C2B51-069A-4FBB-BFE9-42D573F1CEEA} = {28140562-A65A-48E9-ABAB-53BA939084F0} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {19706846-1F47-42ED-B649-B0982EE96E6B} EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + ..\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{71ab8240-f179-4b21-a8be-8be6cd774ed9}*SharedItemsImports = 5 + EndGlobalSection EndGlobal From 19c046315e8a5a719dabc4f2c5061b8e4bac356f Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Fri, 9 Dec 2022 17:20:14 -0600 Subject: [PATCH 04/39] Making progress --- .../src/System/Numerics/Decimal32.cs | 214 ++++++++++++++++-- 1 file changed, 195 insertions(+), 19 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index 7ba8971da6585d..30aeddb18ab657 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -8,7 +8,10 @@ namespace System.Numerics { - [Serializable] + /// + /// An IEEE 754 compliant float16 type. + /// + [Serializable] // TODO do we need this? Half doesn't have it, Single does. [StructLayout(LayoutKind.Sequential)] public readonly struct Decimal32 : IComparable, @@ -19,23 +22,152 @@ public readonly struct Decimal32 IDecimalFloatingPointIeee754, IMinMaxValue { - private readonly uint _value; + // Constants for manipulating the private bit-representation + // TODO I think adding masks that help us "triage" the type of encoding will be useful. - public static Decimal32 MaxValue => throw new NotImplementedException(); + internal const uint SignMask = 0x8000_0000; + internal const int SignShift = 31; - public static Decimal32 MinValue => throw new NotImplementedException(); + internal const uint CombinationMask = 0x7FF0_0000; + internal const int CombinationShift = 20; - public static Decimal32 Epsilon => throw new NotImplementedException(); + // TODO figure out if these three are useful, I don't think they are + internal const uint NaNMask = 0x7C00_0000; + internal const uint InfinityMask = 0x7800_0000; + internal const uint TrailingSignificandMask = 0x000F_FFFF; - public static Decimal32 NaN => throw new NotImplementedException(); + // TODO I think these might be useless in Decimal +/* internal const ushort MinCombination = 0x0000; + internal const ushort MaxCombination = 0x07FF;*/ - public static Decimal32 NegativeInfinity => throw new NotImplementedException(); + internal const sbyte EMax = 96; + internal const sbyte EMin = -95; - public static Decimal32 NegativeZero => throw new NotImplementedException(); + internal const byte Precision = 7; + internal const byte ExponentBias = 101; - public static Decimal32 PositiveInfinity => throw new NotImplementedException(); + internal const sbyte MaxQExponent = EMax - Precision + 1; + internal const sbyte MinQExponent = EMin - Precision + 1; - public static Decimal32 NegativeOne => throw new NotImplementedException(); + // TODO I think these might be useless in Decimal + /* internal const uint MinTrailingSignificand = 0x0000_0000; + internal const uint MaxTrailingSignificand = 0x000F_FFFF; // TODO double check this, might be artificially bounded below this*/ + + // Constants representing the private bit-representation for various default values. + // See either IEEE-754 2019 section 3.5 or https://en.wikipedia.org/wiki/Decimal32_floating-point_format for a breakdown of the encoding. + + // PositiveZero Bits + // Hex: 0x0000_0000 + // Binary: 0000_0000_0000_0000_0000_0000_0000_0000 + // Split into sections: 0 | 000_0000_0 | 000_0000_0000_0000_0000_0000 + // 0 | 0000_0000 | 000_0000_0000_0000_0000_0000 + // Section labels: a | b | c + // + // a. Sign bit. + // b. Biased Exponent, which is q + 101. 0000_0000 == 0 == -101 + 101, so this is encoding a q of -101. + // c. Significand, set to 0. + // + // Encoded value: 0 x 10^-101 + + private const uint PositiveZeroBits = 0x0000_0000; + private const uint NegativeZeroBits = SignMask | PositiveZeroBits; + + + // Epsilon Bits + // Hex: 0x0000_0001 + // Binary: 0000_0000_0000_0000_0000_0000_0000_0001 + // Split into sections: 0 | 000_0000_0 | 000_0000_0000_0000_0000_0001 + // 0 | 0000_0000 | 000_0000_0000_0000_0000_0001 + // Section labels: a | b | c + // + // a. Sign bit. + // b. Biased Exponent, which is q + 101. 0000_0000 == 0 == -101 + 101, so this is encoding a q of -101. + // c. Significand, set to 1. + // + // Encoded value: 1 x 10^-101 + + private const uint EpsilonBits = 0x0000_0001; + + // PositiveInfinityBits + // Hex: 0x7800_0000 + // Binary: 0111_1000_0000_0000_0000_0000_0000_0000 + // Split into sections: 0 | 111_1000_0000 | 0000_0000_0000_0000_0000 + // Section labels: a | b | c + // + // a. Sign bit. + // b. Combination field G0 through G10. G0-G4 == 11110 encodes infinity. + // c. Trailing significand. + // Note: Canonical infinity has everything after G5 set to 0. + private const uint PositiveInfinityBits = 0x7800_0000; + private const uint NegativeInfinityBits = SignMask | PositiveInfinityBits; + + + // QNanBits + // Hex: 0x7C00_0000 + // Binary: 0111_1100_0000_0000_0000_0000_0000_0000 + // Split into sections: 0 | 111_1100_0000 | 0000_0000_0000_0000_0000 + // Section labels: a | b | c + // + // a. Sign bit (ignored for NaN). + // b. Combination field G0 through G10. G0-G4 == 11111 encodes NaN. + // c. Trailing significand. Can be used to encode a payload, to distinguish different NaNs. + // Note: Canonical NaN has G6-G10 as 0 and the encoding of the payload also canonical. + private const uint QNanBits = 0x7C00_0000; // TODO I used a "positive" NaN here, should it be negative? + private const uint SNanBits = 0x7E00_0000; + + + // MaxValueBits + // Hex: 0x77F8_967F + // Binary: 0111_0111_1111_1000_1001_0110_0111_1111 + // Split into sections: 0 | 11 | 1_0111_111 | 1_1000_1001_0110_0111_1111 + // 0 | 11 | 1011_1111 | [100]1_1000_1001_0110_0111_1111 + // Section labels: a | b | c | d + // + // a. Sign bit. + // b. G0 and G1 of the combination field, "11" indicates this version of encoding. + // c. Biased Exponent, which is q + 101. 1011_1111 == 191 == 90 + 101, so this is encoding an q of 90. + // d. Significand. Section b. indicates an implied prefix of [100]. [100]1_1000_1001_0110_0111_1111 == 9,999,999. + // + // Encoded value: 9,999,999 x 10^90 + private const uint MaxValueBits = 0x77F8_967F; + private const uint MinValueBits = SignMask | MaxValueBits; + + // PositiveOneBits Bits + // Hex: 0x3280_0001 + // Binary: 0011_0010_1000_0000_0000_0000_0000_0001 + // Split into sections: 0 | 011_0010_1 | 000_0000_0000_0000_0000_0001 + // 0 | 0110_0101 | 000_0000_0000_0000_0000_0001 + // Section labels: a | b | c + // + // a. Sign bit. + // b. Biased Exponent, which is q + 101. 0110_0101 == 101 == 0 + 101, so this is encoding an q of 0. + // c. Significand, set to 1. + // + // Encoded value: 1 x 10^0 + private const uint PositiveOneBits = 0x3280_0001; + private const uint NegativeOneBits = SignMask | PositiveOneBits; + /* + private const uint EBits = 0; // TODO + private const uint PiBits = 0; // TODO + private const uint TauBits = 0; // TODO*/ + + // Well-defined and commonly used values + + public static Decimal32 MaxValue => new Decimal32(MaxValueBits); // 9.999999E90 + + public static Decimal32 MinValue => new Decimal32(MinValueBits); // -9.999999E90 + + public static Decimal32 Epsilon => new Decimal32(EpsilonBits); // 1E-101 + + public static Decimal32 NaN => new Decimal32(QNanBits); // 0.0 / 0.0 + + public static Decimal32 NegativeInfinity => new Decimal32(NegativeInfinityBits); // -1.0 / 0.0 + + public static Decimal32 NegativeZero => new Decimal32(NegativeZeroBits); // -0E-101 + + public static Decimal32 PositiveInfinity => new Decimal32(PositiveInfinityBits); // 1.0 / 0.0 + + public static Decimal32 NegativeOne => new Decimal32(NegativeOneBits); // -1E0 public static Decimal32 E => throw new NotImplementedException(); @@ -43,17 +175,38 @@ public readonly struct Decimal32 public static Decimal32 Tau => throw new NotImplementedException(); - public static Decimal32 One => throw new NotImplementedException(); + public static Decimal32 One => new Decimal32(PositiveOneBits); // 1E0 - public static int Radix => throw new NotImplementedException(); + public static int Radix => 10; - public static Decimal32 Zero => throw new NotImplementedException(); + public static Decimal32 Zero => new Decimal32(PositiveZeroBits); // -0E-101 - public static Decimal32 AdditiveIdentity => throw new NotImplementedException(); + public static Decimal32 AdditiveIdentity => new Decimal32(PositiveZeroBits); // TODO do we want to make sure this is a zero such that the quantum of any other value is preserved on addition? - public static Decimal32 MultiplicativeIdentity => throw new NotImplementedException(); + public static Decimal32 MultiplicativeIdentity => new Decimal32(PositiveZeroBits); // TODO do we want to make sure this is a zero such that the quantum of any other value is preserved on addition? + + internal readonly uint _value; // TODO: Single places this at the top, Half places it here. Also, Single has this as private, Half has it as internal. What do we want? + + // Private Constructors + + internal Decimal32(uint value) + { + _value = value; + } + + private Decimal32(bool sign, uint combination, uint trailing_sig) => _value = (uint)(((sign ? 1 : 0) << SignShift) + (combination << CombinationShift) + trailing_sig); // TODO do we need this? + private Decimal32(bool sign, uint q, uint sig) + { + // Edge conditions: MinQExponent <= q <= MaxQExponent, 0 <= sig <= 9999999 + _value = 0; // TODO + } + + /// + public static Decimal32 Abs(Decimal32 value) + { + return new Decimal32(value._value & ~SignMask); + } - public static Decimal32 Abs(Decimal32 value) => throw new NotImplementedException(); public static Decimal32 Acos(Decimal32 x) => throw new NotImplementedException(); public static Decimal32 Acosh(Decimal32 x) => throw new NotImplementedException(); public static Decimal32 AcosPi(Decimal32 x) => throw new NotImplementedException(); @@ -65,6 +218,7 @@ public readonly struct Decimal32 public static Decimal32 Atan2Pi(Decimal32 y, Decimal32 x) => throw new NotImplementedException(); public static Decimal32 Atanh(Decimal32 x) => throw new NotImplementedException(); public static Decimal32 AtanPi(Decimal32 x) => throw new NotImplementedException(); + /// public static Decimal32 BitDecrement(Decimal32 x) => throw new NotImplementedException(); public static Decimal32 BitIncrement(Decimal32 x) => throw new NotImplementedException(); public static Decimal32 Cbrt(Decimal32 x) => throw new NotImplementedException(); @@ -127,9 +281,31 @@ public readonly struct Decimal32 public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); - static bool INumberBase.TryConvertFromChecked(TOther value, out Decimal32 result) => throw new NotImplementedException(); - static bool INumberBase.TryConvertFromSaturating(TOther value, out Decimal32 result) => throw new NotImplementedException(); - static bool INumberBase.TryConvertFromTruncating(TOther value, out Decimal32 result) => throw new NotImplementedException(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static bool INumberBase.TryConvertFromChecked(TOther value, out Decimal32 result) + { + return TryConvertFrom(value, out result); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static bool INumberBase.TryConvertFromSaturating(TOther value, out Decimal32 result) + { + return TryConvertFrom(value, out result); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static bool INumberBase.TryConvertFromTruncating(TOther value, out Decimal32 result) + { + return TryConvertFrom(value, out result); + } + private static bool TryConvertFrom(TOther value, out Decimal32 result) + where TOther : INumberBase + { + // TODO + } static bool INumberBase.TryConvertToChecked(Decimal32 value, out TOther result) => throw new NotImplementedException(); static bool INumberBase.TryConvertToSaturating(Decimal32 value, out TOther result) => throw new NotImplementedException(); static bool INumberBase.TryConvertToTruncating(Decimal32 value, out TOther result) => throw new NotImplementedException(); From 142221d55089aa4277ce110d84371264e70e4eb5 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Wed, 14 Dec 2022 20:06:02 -0600 Subject: [PATCH 05/39] Started fleshing out IeeeDecimalNumber.cs --- .../src/System/Numerics/IeeeDecimalNumber.cs | 254 ++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs new file mode 100644 index 00000000000000..f8d70f4da9654f --- /dev/null +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs @@ -0,0 +1,254 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// The IeeeDecimalNumber class implements methods for formatting and parsing IEEE decimal types. +// If these types lived in the System namespace, these methods would live in Number.Parsing.cs and Number.Formatting.cs, +// just like Single, Double, and Half. + +using System.Buffers; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Text; +using System.Runtime.CompilerServices; + +namespace System.Numerics +{ + internal static class IeeeDecimalNumber + { + + // IeeeDecimalNumberBuffer + + internal const int Decimal32BufferLength = 0 + 1 + 1; // TODO: X for the longest input + 1 for rounding (+1 for the null terminator) + + internal unsafe ref struct IeeeDecimalNumberBuffer + { + public int DigitsCount; + public int Scale; + public bool IsNegative; + public bool HasNonZeroTail; + public Span Digits; + + public IeeeDecimalNumberBuffer(byte* digits, int digitsLength) : this(new Span(digits, digitsLength)) + { + Debug.Assert(digits != null); + } + + /// Initializes the NumberBuffer. + /// The digits scratch space. The referenced memory must not be movable, e.g. stack memory, pinned array, etc. + public IeeeDecimalNumberBuffer(Span digits) + { + Debug.Assert(!digits.IsEmpty); + + DigitsCount = 0; + Scale = 0; + IsNegative = false; + HasNonZeroTail = false; + Digits = digits; +#if DEBUG + Digits.Fill(0xCC); +#endif + Digits[0] = (byte)'\0'; + CheckConsistency(); + } + +#pragma warning disable CA1822 + [Conditional("DEBUG")] + public void CheckConsistency() // TODO do we want this? + { +#if DEBUG + Debug.Assert(Digits[0] != '0', "Leading zeros should never be stored in a IeeeDecimalNumber"); + + int numDigits; + for (numDigits = 0; numDigits < Digits.Length; numDigits++) + { + byte digit = Digits[numDigits]; + + if (digit == 0) + { + break; + } + + Debug.Assert(char.IsAsciiDigit((char)digit), $"Unexpected character found in IeeeDecimalNumber: {digit}"); + } + + Debug.Assert(numDigits == DigitsCount, "Null terminator found in unexpected location in IeeeDecimalNumber"); + Debug.Assert(numDigits < Digits.Length, "Null terminator not found in IeeeDecimalNumber"); +#endif // DEBUG + } +#pragma warning restore CA1822 + +#pragma warning disable CA1822 // TODO I don't know why this is required, it isn't for Number.NumberBuffer.cs + public byte* GetDigitsPointer() // TODO this is complaining that the method could be static, but it is wrong + { + // This is safe to do since we are a ref struct + return (byte*)(Unsafe.AsPointer(ref Digits[0])); + } +#pragma warning restore CA1822 + + // + // Code coverage note: This only exists so that Number displays nicely in the VS watch window. So yes, I know it works. + // + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + + sb.Append('['); + sb.Append('"'); + + for (int i = 0; i < Digits.Length; i++) + { + byte digit = Digits[i]; + + if (digit == 0) + { + break; + } + + sb.Append((char)(digit)); + } + + sb.Append('"'); + sb.Append(", Length = ").Append(DigitsCount); + sb.Append(", Scale = ").Append(Scale); + sb.Append(", IsNegative = ").Append(IsNegative); + sb.Append(", HasNonZeroTail = ").Append(HasNonZeroTail); + sb.Append(']'); + + return sb.ToString(); + } + } + + // IeeeDecimalNumber Parsing TODO potentially rewrite this + + // The Parse methods provided by the numeric classes convert a + // string to a numeric value. The optional style parameter specifies the + // permitted style of the numeric string. It must be a combination of bit flags + // from the NumberStyles enumeration. The optional info parameter + // specifies the NumberFormatInfo instance to use when parsing the + // string. If the info parameter is null or omitted, the numeric + // formatting information is obtained from the current culture. + // + // Numeric strings produced by the Format methods using the Currency, + // Decimal, Engineering, Fixed point, General, or Number standard formats + // (the C, D, E, F, G, and N format specifiers) are guaranteed to be parseable + // by the Parse methods if the NumberStyles.Any style is + // specified. Note, however, that the Parse methods do not accept + // NaNs or Infinities. + + [DoesNotReturn] + internal static void ThrowFormatException(ParsingStatus status, ReadOnlySpan value, TypeCode type = 0) => throw new FormatException(SR.Format(SR.Format_InvalidStringWithValue, value.ToString())); + + internal static Half ParseDecimal32(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info) + { + if (!TryParseDecimal32(value, styles, info, out Decimal32 result)) + { + ThrowFormatException(ParsingStatus.Failed, value); + } + + return result; + } + + internal static unsafe bool TryParseDecimal32(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out Decimal32 result) + { + IeeeDecimalNumberBuffer number = new IeeeDecimalNumberBuffer(NumberBufferKind.FloatingPoint, stackalloc byte[HalfNumberBufferLength]); + + if (!TryStringToNumber(value, styles, ref number, info)) + { + ReadOnlySpan valueTrim = value.Trim(); + + // This code would be simpler if we only had the concept of `InfinitySymbol`, but + // we don't so we'll check the existing cases first and then handle `PositiveSign` + + // `PositiveInfinitySymbol` and `PositiveSign/NegativeSign` + `NaNSymbol` last. + // + // Additionally, since some cultures ("wo") actually define `PositiveInfinitySymbol` + // to include `PositiveSign`, we need to check whether `PositiveInfinitySymbol` fits + // that case so that we don't start parsing things like `++infini`. + + if (valueTrim.EqualsOrdinalIgnoreCase(info.PositiveInfinitySymbol)) + { + result = Half.PositiveInfinity; + } + else if (valueTrim.EqualsOrdinalIgnoreCase(info.NegativeInfinitySymbol)) + { + result = Half.NegativeInfinity; + } + else if (valueTrim.EqualsOrdinalIgnoreCase(info.NaNSymbol)) + { + result = Half.NaN; + } + else if (valueTrim.StartsWith(info.PositiveSign, StringComparison.OrdinalIgnoreCase)) + { + valueTrim = valueTrim.Slice(info.PositiveSign.Length); + + if (!info.PositiveInfinitySymbol.StartsWith(info.PositiveSign, StringComparison.OrdinalIgnoreCase) && valueTrim.EqualsOrdinalIgnoreCase(info.PositiveInfinitySymbol)) + { + result = Half.PositiveInfinity; + } + else if (!info.NaNSymbol.StartsWith(info.PositiveSign, StringComparison.OrdinalIgnoreCase) && valueTrim.EqualsOrdinalIgnoreCase(info.NaNSymbol)) + { + result = Half.NaN; + } + else + { + result = Half.Zero; + return false; + } + } + else if (valueTrim.StartsWith(info.NegativeSign, StringComparison.OrdinalIgnoreCase) && + !info.NaNSymbol.StartsWith(info.NegativeSign, StringComparison.OrdinalIgnoreCase) && + valueTrim.Slice(info.NegativeSign.Length).EqualsOrdinalIgnoreCase(info.NaNSymbol)) + { + result = Half.NaN; + } + else if (info.AllowHyphenDuringParsing && SpanStartsWith(valueTrim, '-') && !info.NaNSymbol.StartsWith(info.NegativeSign, StringComparison.OrdinalIgnoreCase) && + !info.NaNSymbol.StartsWith('-') && valueTrim.Slice(1).EqualsOrdinalIgnoreCase(info.NaNSymbol)) + { + result = Half.NaN; + } + else + { + result = Half.Zero; + return false; // We really failed + } + } + else + { + result = NumberToHalf(ref number); + } + + return true; + } + + internal static Decimal32 NumberToDecimal32(ref NumberBuffer number) + { + number.CheckConsistency(); + Decimal32 result; + + if ((number.DigitsCount == 0) || (number.Scale < Decimal32MinExponent)) + { + result = default; + } + else if (number.Scale > Decimal32MaxExponent) + { + result = Decimal32.PositiveInfinity; + } + else + { + ushort bits = NumberToDecimal32FloatingPointBits(ref number, in FloatingPointInfo.Decimal32); + result = new Decimal32(bits); + } + + return number.IsNegative ? Decimal32.Negate(result) : result; + } + + internal enum ParsingStatus // No Overflow because these types can represent Infinity + { + OK, + Failed + } + + // IeeeDecimalNumber Formatting + } +} From 0c592f2021f7b03a5c9e7880634a9ed7e2ecc6ca Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Wed, 14 Dec 2022 20:06:19 -0600 Subject: [PATCH 06/39] More progress including Parse and TryParse --- .../src/System/Numerics/Decimal32.cs | 621 +++++++++++++++++- 1 file changed, 601 insertions(+), 20 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index 30aeddb18ab657..1913335a1d1812 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -257,10 +257,71 @@ public static Decimal32 Abs(Decimal32 value) public static Decimal32 MaxMagnitudeNumber(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); public static Decimal32 MinMagnitude(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); public static Decimal32 MinMagnitudeNumber(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); - public static Decimal32 Parse(ReadOnlySpan s, IFormatProvider? provider) => throw new NotImplementedException(); - public static Decimal32 Parse(string s, IFormatProvider? provider) => throw new NotImplementedException(); - public static Decimal32 Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider) => throw new NotImplementedException(); - public static Decimal32 Parse(string s, NumberStyles style, IFormatProvider? provider) => throw new NotImplementedException(); + + // + // Parsing (INumberBase, IParsable, ISpanParsable) + // + + /// + public static Decimal32 Parse(ReadOnlySpan s, IFormatProvider? provider) + { + // NumberFormatInfo.ValidateParseStyleFloatingPoint(NumberStyles.Number); // TODO, it won't let me call this because it's internal to System. + return IeeeDecimalNumber.ParseDecimal32(s, NumberStyles.Number, NumberFormatInfo.GetInstance(provider)); + } + + /// + public static Decimal32 Parse(string s, IFormatProvider? provider) + { + // if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); // TODO, it won't let me call this because it's internal to System. + return IeeeDecimalNumber.ParseDecimal32(s, NumberStyles.Number, NumberFormatInfo.GetInstance(provider)); + } + + /// + public static Decimal32 Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider = null) // TODO what should the default for NumberStyles be? + { + // NumberFormatInfo.ValidateParseStyleFloatingPoint(style); // TODO, it won't let me call this because it's internal to System. + return IeeeDecimalNumber.ParseDecimal32(s, style, NumberFormatInfo.GetInstance(provider)); + } + + /// + public static Decimal32 Parse(string s, NumberStyles style, IFormatProvider? provider) + { + // NumberFormatInfo.ValidateParseStyleFloatingPoint(style); // TODO, it won't let me call these because they are internal to System. + // if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); + return IeeeDecimalNumber.ParseDecimal32(s, style, NumberFormatInfo.GetInstance(provider)); + } + + /// + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) + { + // NumberFormatInfo.ValidateParseStyleFloatingPoint(NumberStyles.Number); // TODO + return IeeeDecimalNumber.TryParseDecimal32(s, NumberStyles.Number, NumberFormatInfo.GetInstance(provider), out result) == IeeeDecimalNumber.ParsingStatus.OK; + } + + /// + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => TryParse(s, NumberStyles.Number, provider, out result); + + /// + public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) + { + // NumberFormatInfo.ValidateParseStyleFloatingPoint(style); // TODO + return IeeeDecimalNumber.TryParseDecimal32(s, style, NumberFormatInfo.GetInstance(provider), out result) == IeeeDecimalNumber.ParsingStatus.OK; + } + + /// + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) + { + // NumberFormatInfo.ValidateParseStyleFloatingPoint(style); // TODO + + if (s == null) + { + result = 0; + return false; + } + + return IeeeDecimalNumber.TryParseDecimal32(s, style, NumberFormatInfo.GetInstance(provider), out result) == IeeeDecimalNumber.ParsingStatus.OK; + } + public static Decimal32 Pow(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); public static Decimal32 Quantize(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); public static Decimal32 Quantum(Decimal32 x) => throw new NotImplementedException(); @@ -277,38 +338,558 @@ public static Decimal32 Abs(Decimal32 value) public static Decimal32 Tan(Decimal32 x) => throw new NotImplementedException(); public static Decimal32 Tanh(Decimal32 x) => throw new NotImplementedException(); public static Decimal32 TanPi(Decimal32 x) => throw new NotImplementedException(); - public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); - public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); - public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); - public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => throw new NotImplementedException(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Decimal32 CreateChecked(TOther value) // TODO these are copy-pastes of the DIM. Do we still want them? + where TOther : INumberBase + { + Decimal32 result; + + if (typeof(TOther) == typeof(Decimal32)) + { + result = (Decimal32)(object)value; + } + else if (!TryConvertFromChecked(value, out result) && !TOther.TryConvertToChecked(value, out result)) + { + ThrowHelper.ThrowNotSupportedException(); + } + + return result; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Decimal32 CreateSaturating(TOther value) + where TOther : INumberBase + { + Decimal32 result; + + if (typeof(TOther) == typeof(Decimal32)) + { + result = (Decimal32)(object)value; + } + else if (!TryConvertFromSaturating(value, out result) && !TOther.TryConvertToSaturating(value, out result)) + { + ThrowHelper.ThrowNotSupportedException(); + } + + return result; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Decimal32 CreateTruncating(TOther value) + where TOther : INumberBase + { + Decimal32 result; + + if (typeof(TOther) == typeof(Decimal32)) + { + result = (Decimal32)(object)value; + } + else if (!TryConvertFromTruncating(value, out result) && !TOther.TryConvertToTruncating(value, out result)) + { + ThrowHelper.ThrowNotSupportedException(); + } + + return result; + } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - static bool INumberBase.TryConvertFromChecked(TOther value, out Decimal32 result) + static bool INumberBase.TryConvertFromChecked(TOther value, out Decimal32 result) => TryConvertFromChecked(value, out result); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryConvertFromChecked(TOther value, out Decimal32 result) + where TOther : INumberBase { - return TryConvertFrom(value, out result); + if (typeof(TOther) == typeof(byte)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(char)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(decimal)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(double)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(Half)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(short)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(int)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(long)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(Int128)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(nint)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(sbyte)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(float)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(ushort)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(uint)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(ulong)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(UInt128)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(nuint)) + { + throw new NotImplementedException(); + } + else + { + result = default; + return false; + } } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - static bool INumberBase.TryConvertFromSaturating(TOther value, out Decimal32 result) + static bool INumberBase.TryConvertFromSaturating(TOther value, out Decimal32 result) => TryConvertFromSaturating(value, out result); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryConvertFromSaturating(TOther value, out Decimal32 result) + where TOther : INumberBase { - return TryConvertFrom(value, out result); + if (typeof(TOther) == typeof(byte)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(char)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(decimal)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(double)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(Half)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(short)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(int)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(long)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(Int128)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(nint)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(sbyte)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(float)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(ushort)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(uint)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(ulong)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(UInt128)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(nuint)) + { + throw new NotImplementedException(); + } + else + { + result = default; + return false; + } } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - static bool INumberBase.TryConvertFromTruncating(TOther value, out Decimal32 result) + static bool INumberBase.TryConvertFromTruncating(TOther value, out Decimal32 result) => TryConvertFromTruncating(value, out result); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryConvertFromTruncating(TOther value, out Decimal32 result) + where TOther : INumberBase { - return TryConvertFrom(value, out result); + if (typeof(TOther) == typeof(byte)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(char)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(decimal)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(double)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(Half)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(short)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(int)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(long)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(Int128)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(nint)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(sbyte)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(float)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(ushort)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(uint)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(ulong)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(UInt128)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(nuint)) + { + throw new NotImplementedException(); + } + else + { + result = default; + return false; + } } - private static bool TryConvertFrom(TOther value, out Decimal32 result) - where TOther : INumberBase + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static bool INumberBase.TryConvertToChecked(Decimal32 value, [MaybeNullWhen(false)] out TOther result) + { + if (typeof(TOther) == typeof(byte)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(char)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(decimal)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(double)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(Half)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(short)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(int)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(long)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(Int128)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(nint)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(sbyte)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(float)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(ushort)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(uint)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(ulong)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(UInt128)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(nuint)) + { + throw new NotImplementedException(); + } + else + { + result = default; + return false; + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static bool INumberBase.TryConvertToSaturating(Decimal32 value, [MaybeNullWhen(false)] out TOther result) + { + if (typeof(TOther) == typeof(byte)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(char)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(decimal)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(double)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(Half)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(short)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(int)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(long)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(Int128)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(nint)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(Complex)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(sbyte)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(float)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(ushort)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(uint)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(ulong)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(UInt128)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(nuint)) + { + throw new NotImplementedException(); + } + else + { + result = default; + return false; + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static bool INumberBase.TryConvertToTruncating(Decimal32 value, [MaybeNullWhen(false)] out TOther result) { - // TODO + if (typeof(TOther) == typeof(byte)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(char)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(decimal)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(double)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(Half)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(short)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(int)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(long)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(Int128)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(nint)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(Complex)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(sbyte)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(float)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(ushort)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(uint)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(ulong)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(UInt128)) + { + throw new NotImplementedException(); + } + else if (typeof(TOther) == typeof(nuint)) + { + throw new NotImplementedException(); + } + else + { + result = default; + return false; + } } - static bool INumberBase.TryConvertToChecked(Decimal32 value, out TOther result) => throw new NotImplementedException(); - static bool INumberBase.TryConvertToSaturating(Decimal32 value, out TOther result) => throw new NotImplementedException(); - static bool INumberBase.TryConvertToTruncating(Decimal32 value, out TOther result) => throw new NotImplementedException(); + public int CompareTo(Decimal32 other) => throw new NotImplementedException(); public int CompareTo(object? obj) => throw new NotImplementedException(); public bool Equals(Decimal32 other) => throw new NotImplementedException(); From e60fbfa8951c40b53ac40ed0125482d7eb6dc551 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Fri, 16 Dec 2022 17:04:47 -0600 Subject: [PATCH 07/39] continue to work on parsing --- .../src/System/Numerics/Decimal32.cs | 6 + .../src/System/Numerics/IeeeDecimalNumber.cs | 426 +++++++++++++++++- 2 files changed, 415 insertions(+), 17 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index 1913335a1d1812..91c1a10a7259e4 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -931,5 +931,11 @@ public override int GetHashCode() } public string ToString(string? format, IFormatProvider? formatProvider) => throw new NotImplementedException(); + + // IEEE 754 specifies NaNs to be propagated + internal static Decimal32 Negate(Decimal32 value) + { + return IsNaN(value) ? value : new Decimal32((ushort)(value._value ^ SignMask)); + } } } diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs index f8d70f4da9654f..0274b3ed1c14f8 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs @@ -120,7 +120,7 @@ public override string ToString() } } - // IeeeDecimalNumber Parsing TODO potentially rewrite this + // IeeeDecimalNumber Parsing TODO potentially rewrite this description // The Parse methods provided by the numeric classes convert a // string to a numeric value. The optional style parameter specifies the @@ -140,7 +140,7 @@ public override string ToString() [DoesNotReturn] internal static void ThrowFormatException(ParsingStatus status, ReadOnlySpan value, TypeCode type = 0) => throw new FormatException(SR.Format(SR.Format_InvalidStringWithValue, value.ToString())); - internal static Half ParseDecimal32(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info) + internal static Decimal32 ParseDecimal32(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info) { if (!TryParseDecimal32(value, styles, info, out Decimal32 result)) { @@ -152,7 +152,7 @@ internal static Half ParseDecimal32(ReadOnlySpan value, NumberStyles style internal static unsafe bool TryParseDecimal32(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out Decimal32 result) { - IeeeDecimalNumberBuffer number = new IeeeDecimalNumberBuffer(NumberBufferKind.FloatingPoint, stackalloc byte[HalfNumberBufferLength]); + IeeeDecimalNumberBuffer number = new IeeeDecimalNumberBuffer(stackalloc byte[Decimal32BufferLength]); if (!TryStringToNumber(value, styles, ref number, info)) { @@ -168,15 +168,15 @@ internal static unsafe bool TryParseDecimal32(ReadOnlySpan value, NumberSt if (valueTrim.EqualsOrdinalIgnoreCase(info.PositiveInfinitySymbol)) { - result = Half.PositiveInfinity; + result = Decimal32.PositiveInfinity; } else if (valueTrim.EqualsOrdinalIgnoreCase(info.NegativeInfinitySymbol)) { - result = Half.NegativeInfinity; + result = Decimal32.NegativeInfinity; } else if (valueTrim.EqualsOrdinalIgnoreCase(info.NaNSymbol)) { - result = Half.NaN; + result = Decimal32.NaN; } else if (valueTrim.StartsWith(info.PositiveSign, StringComparison.OrdinalIgnoreCase)) { @@ -184,15 +184,15 @@ internal static unsafe bool TryParseDecimal32(ReadOnlySpan value, NumberSt if (!info.PositiveInfinitySymbol.StartsWith(info.PositiveSign, StringComparison.OrdinalIgnoreCase) && valueTrim.EqualsOrdinalIgnoreCase(info.PositiveInfinitySymbol)) { - result = Half.PositiveInfinity; + result = Decimal32.PositiveInfinity; } else if (!info.NaNSymbol.StartsWith(info.PositiveSign, StringComparison.OrdinalIgnoreCase) && valueTrim.EqualsOrdinalIgnoreCase(info.NaNSymbol)) { - result = Half.NaN; + result = Decimal32.NaN; } else { - result = Half.Zero; + result = Decimal32.Zero; return false; } } @@ -200,37 +200,350 @@ internal static unsafe bool TryParseDecimal32(ReadOnlySpan value, NumberSt !info.NaNSymbol.StartsWith(info.NegativeSign, StringComparison.OrdinalIgnoreCase) && valueTrim.Slice(info.NegativeSign.Length).EqualsOrdinalIgnoreCase(info.NaNSymbol)) { - result = Half.NaN; + result = Decimal32.NaN; } else if (info.AllowHyphenDuringParsing && SpanStartsWith(valueTrim, '-') && !info.NaNSymbol.StartsWith(info.NegativeSign, StringComparison.OrdinalIgnoreCase) && !info.NaNSymbol.StartsWith('-') && valueTrim.Slice(1).EqualsOrdinalIgnoreCase(info.NaNSymbol)) { - result = Half.NaN; + result = Decimal32.NaN; } else { - result = Half.Zero; + result = Decimal32.Zero; return false; // We really failed } } else { - result = NumberToHalf(ref number); + result = NumberToDecimal32(ref number); } return true; } - internal static Decimal32 NumberToDecimal32(ref NumberBuffer number) + internal static unsafe bool TryStringToNumber(ReadOnlySpan value, NumberStyles styles, ref IeeeDecimalNumberBuffer number, NumberFormatInfo info) + { + Debug.Assert(info != null); + fixed (char* stringPointer = &MemoryMarshal.GetReference(value)) + { + char* p = stringPointer; + if (!TryParseNumber(ref p, p + value.Length, styles, ref number, info) + || ((int)(p - stringPointer) < value.Length && !TrailingZeros(value, (int)(p - stringPointer)))) + { + number.CheckConsistency(); + return false; + } + } + + number.CheckConsistency(); + return true; + } + + // This is almost a direct copy paste of the one in Number.Parsing.cs + private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, NumberStyles styles, ref IeeeDecimalNumberBuffer number, NumberFormatInfo info) + { + Debug.Assert(str != null); + Debug.Assert(strEnd != null); + Debug.Assert(str <= strEnd); + Debug.Assert((styles & NumberStyles.AllowHexSpecifier) == 0); + + const int StateSign = 0x0001; + const int StateParens = 0x0002; + const int StateDigits = 0x0004; + const int StateNonZero = 0x0008; + const int StateDecimal = 0x0010; + const int StateCurrency = 0x0020; + + Debug.Assert(number.DigitsCount == 0); + Debug.Assert(number.Scale == 0); + Debug.Assert(!number.IsNegative); + Debug.Assert(!number.HasNonZeroTail); + + number.CheckConsistency(); + + string decSep; // decimal separator from NumberFormatInfo. + string groupSep; // group separator from NumberFormatInfo. + string? currSymbol = null; // currency symbol from NumberFormatInfo. + + bool parsingCurrency = false; + if ((styles & NumberStyles.AllowCurrencySymbol) != 0) + { + currSymbol = info.CurrencySymbol; + + // The idea here is to match the currency separators and on failure match the number separators to keep the perf of VB's IsNumeric fast. + // The values of decSep are setup to use the correct relevant separator (currency in the if part and decimal in the else part). + decSep = info.CurrencyDecimalSeparator; + groupSep = info.CurrencyGroupSeparator; + parsingCurrency = true; + } + else + { + decSep = info.NumberDecimalSeparator; + groupSep = info.NumberGroupSeparator; + } + + int state = 0; + char* p = str; + char ch = p < strEnd ? *p : '\0'; + char* next; + + while (true) + { + // Eat whitespace unless we've found a sign which isn't followed by a currency symbol. + // "-Kr 1231.47" is legal but "- 1231.47" is not. + if (!IsWhite(ch) || (styles & NumberStyles.AllowLeadingWhite) == 0 || ((state & StateSign) != 0 && ((state & StateCurrency) == 0 && info.NumberNegativePattern != 2))) + { + if ((((styles & NumberStyles.AllowLeadingSign) != 0) && (state & StateSign) == 0) && ((next = MatchChars(p, strEnd, info.PositiveSign)) != null || ((next = MatchNegativeSignChars(p, strEnd, info)) != null && (number.IsNegative = true)))) + { + state |= StateSign; + p = next - 1; + } + else if (ch == '(' && ((styles & NumberStyles.AllowParentheses) != 0) && ((state & StateSign) == 0)) + { + state |= StateSign | StateParens; + number.IsNegative = true; + } + else if (currSymbol != null && (next = MatchChars(p, strEnd, currSymbol)) != null) + { + state |= StateCurrency; + currSymbol = null; + // We already found the currency symbol. There should not be more currency symbols. Set + // currSymbol to NULL so that we won't search it again in the later code path. + p = next - 1; + } + else + { + break; + } + } + ch = ++p < strEnd ? *p : '\0'; + } + + int digCount = 0; + int digEnd = 0; + int maxDigCount = number.Digits.Length - 1; + int numberOfTrailingZeros = 0; + + while (true) + { + if (IsDigit(ch)) + { + state |= StateDigits; + + if (ch != '0' || (state & StateNonZero) != 0) + { + if (digCount < maxDigCount) + { + number.Digits[digCount] = (byte)(ch); + if ((ch != '0') || (number.Kind != NumberBufferKind.Integer)) + { + digEnd = digCount + 1; + } + } + else if (ch != '0') + { + // For decimal and binary floating-point numbers, we only + // need to store digits up to maxDigCount. However, we still + // need to keep track of whether any additional digits past + // maxDigCount were non-zero, as that can impact rounding + // for an input that falls evenly between two representable + // results. + + number.HasNonZeroTail = true; + } + + if ((state & StateDecimal) == 0) + { + number.Scale++; + } + + if (digCount < maxDigCount) + { + // Handle a case like "53.0". We need to ignore trailing zeros in the fractional part for floating point numbers, so we keep a count of the number of trailing zeros and update digCount later + if (ch == '0') + { + numberOfTrailingZeros++; + } + else + { + numberOfTrailingZeros = 0; + } + } + digCount++; + state |= StateNonZero; + } + else if ((state & StateDecimal) != 0) + { + number.Scale--; + } + } + else if (((styles & NumberStyles.AllowDecimalPoint) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, strEnd, decSep)) != null || (parsingCurrency && (state & StateCurrency) == 0) && (next = MatchChars(p, strEnd, info.NumberDecimalSeparator)) != null)) + { + state |= StateDecimal; + p = next - 1; + } + else if (((styles & NumberStyles.AllowThousands) != 0) && ((state & StateDigits) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, strEnd, groupSep)) != null || (parsingCurrency && (state & StateCurrency) == 0) && (next = MatchChars(p, strEnd, info.NumberGroupSeparator)) != null)) + { + p = next - 1; + } + else + { + break; + } + ch = ++p < strEnd ? *p : '\0'; + } + + bool negExp = false; + number.DigitsCount = digEnd; + number.Digits[digEnd] = (byte)('\0'); + if ((state & StateDigits) != 0) + { + if ((ch == 'E' || ch == 'e') && ((styles & NumberStyles.AllowExponent) != 0)) + { + char* temp = p; + ch = ++p < strEnd ? *p : '\0'; + if ((next = MatchChars(p, strEnd, info._positiveSign)) != null) + { + ch = (p = next) < strEnd ? *p : '\0'; + } + else if ((next = MatchNegativeSignChars(p, strEnd, info)) != null) + { + ch = (p = next) < strEnd ? *p : '\0'; + negExp = true; + } + if (IsDigit(ch)) + { + int exp = 0; + do + { + exp = exp * 10 + (ch - '0'); + ch = ++p < strEnd ? *p : '\0'; + if (exp > 1000) + { + exp = 9999; + while (IsDigit(ch)) + { + ch = ++p < strEnd ? *p : '\0'; + } + } + } while (IsDigit(ch)); + if (negExp) + { + exp = -exp; + } + number.Scale += exp; + } + else + { + p = temp; + ch = p < strEnd ? *p : '\0'; + } + } + + if (number.Kind == NumberBufferKind.FloatingPoint && !number.HasNonZeroTail) + { + // Adjust the number buffer for trailing zeros + int numberOfFractionalDigits = digEnd - number.Scale; + if (numberOfFractionalDigits > 0) + { + numberOfTrailingZeros = Math.Min(numberOfTrailingZeros, numberOfFractionalDigits); + Debug.Assert(numberOfTrailingZeros >= 0); + number.DigitsCount = digEnd - numberOfTrailingZeros; + number.Digits[number.DigitsCount] = (byte)('\0'); + } + } + + while (true) + { + if (!IsWhite(ch) || (styles & NumberStyles.AllowTrailingWhite) == 0) + { + if ((styles & NumberStyles.AllowTrailingSign) != 0 && ((state & StateSign) == 0) && ((next = MatchChars(p, strEnd, info.PositiveSign)) != null || (((next = MatchNegativeSignChars(p, strEnd, info)) != null) && (number.IsNegative = true)))) + { + state |= StateSign; + p = next - 1; + } + else if (ch == ')' && ((state & StateParens) != 0)) + { + state &= ~StateParens; + } + else if (currSymbol != null && (next = MatchChars(p, strEnd, currSymbol)) != null) + { + currSymbol = null; + p = next - 1; + } + else + { + break; + } + } + ch = ++p < strEnd ? *p : '\0'; + } + if ((state & StateParens) == 0) + { + if ((state & StateNonZero) == 0) + { + if (number.Kind != NumberBufferKind.Decimal) + { + number.Scale = 0; + } + if ((number.Kind == NumberBufferKind.Integer) && (state & StateDecimal) == 0) + { + number.IsNegative = false; + } + } + str = p; + return true; + } + } + str = p; + return false; + } + + private static unsafe char* MatchChars(char* p, char* pEnd, string value) + { + Debug.Assert(p != null && pEnd != null && p <= pEnd && value != null); + fixed (char* stringPointer = value) + { + char* str = stringPointer; + if (*str != '\0') + { + // We only hurt the failure case + // This fix is for French or Kazakh cultures. Since a user cannot type 0xA0 or 0x202F as a + // space character we use 0x20 space character instead to mean the same. + while (true) + { + char cp = p < pEnd ? *p : '\0'; + if (cp != *str && !(IsSpaceReplacingChar(*str) && cp == '\u0020')) + { + break; + } + p++; + str++; + if (*str == '\0') + return p; + } + } + } + + return null; + } + + private static bool IsSpaceReplacingChar(char c) => c == '\u00a0' || c == '\u202f'; + + private static bool IsWhite(int ch) => ch == 0x20 || (uint)(ch - 0x09) <= (0x0D - 0x09); + + private static bool IsDigit(int ch) => ((uint)ch - '0') <= 9; + + internal static Decimal32 NumberToDecimal32(ref IeeeDecimalNumberBuffer number) { number.CheckConsistency(); Decimal32 result; - if ((number.DigitsCount == 0) || (number.Scale < Decimal32MinExponent)) + if ((number.DigitsCount == 0) || (number.Scale < Decimal32.MinQExponent)) { result = default; } - else if (number.Scale > Decimal32MaxExponent) + else if (number.Scale > Decimal32.MaxQExponent) { result = Decimal32.PositiveInfinity; } @@ -243,7 +556,86 @@ internal static Decimal32 NumberToDecimal32(ref NumberBuffer number) return number.IsNegative ? Decimal32.Negate(result) : result; } - internal enum ParsingStatus // No Overflow because these types can represent Infinity + private static ushort NumberToDecimal32FloatingPointBits(ref IeeeDecimalNumberBuffer number, in FloatingPointInfo info) + { + Debug.Assert(info.DenormalMantissaBits == 10); + + Debug.Assert(number.GetDigitsPointer()[0] != '0'); + + Debug.Assert(number.Scale <= FloatingPointMaxExponent); + Debug.Assert(number.Scale >= FloatingPointMinExponent); + + Debug.Assert(number.DigitsCount != 0); + + // The input is of the form 0.Mantissa x 10^Exponent, where 'Mantissa' are + // the decimal digits of the mantissa and 'Exponent' is the decimal exponent. + // We decompose the mantissa into two parts: an integer part and a fractional + // part. If the exponent is positive, then the integer part consists of the + // first 'exponent' digits, or all present digits if there are fewer digits. + // If the exponent is zero or negative, then the integer part is empty. In + // either case, the remaining digits form the fractional part of the mantissa. + + uint totalDigits = (uint)(number.DigitsCount); + uint positiveExponent = (uint)(Math.Max(0, number.Scale)); + + uint integerDigitsPresent = Math.Min(positiveExponent, totalDigits); + uint fractionalDigitsPresent = totalDigits - integerDigitsPresent; + + int exponent = (int)(number.Scale - integerDigitsPresent - fractionalDigitsPresent); + int fastExponent = Math.Abs(exponent); + + // Above 19 digits, we rely on slow path + if (totalDigits <= 19) + { + byte* src = number.GetDigitsPointer(); + + // When the number of significant digits is less than or equal to MaxMantissaFastPath and the + // scale is less than or equal to MaxExponentFastPath, we can take some shortcuts and just rely + // on floating-point arithmetic to compute the correct result. This is + // because each floating-point precision values allows us to exactly represent + // different whole integers and certain powers of 10, depending on the underlying + // formats exact range. Additionally, IEEE operations dictate that the result is + // computed to the infinitely precise result and then rounded, which means that + // we can rely on it to produce the correct result when both inputs are exact. + // This is known as Clinger's fast path + + ulong mantissa = DigitsToUInt64(src, (int)(totalDigits)); + + if ((mantissa <= info.MaxMantissaFastPath) && (fastExponent <= info.MaxExponentFastPath)) + { + double mantissa_d = mantissa; + double scale = s_Pow10DoubleTable[fastExponent]; + + if (fractionalDigitsPresent != 0) + { + mantissa_d /= scale; + } + else + { + mantissa_d *= scale; + } + + return BitConverter.HalfToUInt16Bits((Half)(mantissa_d)); + } + + // Number Parsing at a Gigabyte per Second, Software: Practice and Experience 51(8), 2021 + // https://arxiv.org/abs/2101.11408 + (int Exponent, ulong Mantissa) am = ComputeFloat(exponent, mantissa, info); + + // If we called ComputeFloat and we have an invalid power of 2 (Exponent < 0), + // then we need to go the slow way around again. This is very uncommon. + if (am.Exponent > 0) + { + ulong word = am.Mantissa; + word |= (ulong)(uint)(am.Exponent) << info.DenormalMantissaBits; + return (ushort)word; + } + + } + return (ushort)NumberToFloatingPointBitsSlow(ref number, in info, positiveExponent, integerDigitsPresent, fractionalDigitsPresent); + } + + internal enum ParsingStatus // No ParsingStatus.Overflow because these types can represent infinity { OK, Failed From 474cdcb996a3d48e2e78a61988ad0b01e22eede8 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Mon, 19 Dec 2022 11:23:44 -0600 Subject: [PATCH 08/39] Make AllowHyphenDuringParsing public --- .../System/Globalization/NumberFormatInfo.cs | 2 +- .../src/System/Numerics/IeeeDecimalNumber.cs | 26 +++++++++++++++++-- .../System.Runtime/ref/System.Runtime.cs | 1 + 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/NumberFormatInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/NumberFormatInfo.cs index 3d2c60fd01550b..b3ab95500b35c8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/NumberFormatInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/NumberFormatInfo.cs @@ -136,7 +136,7 @@ private static void VerifyDigitSubstitution(DigitShapes digitSub, string propert } internal bool HasInvariantNumberSigns => _hasInvariantNumberSigns; - internal bool AllowHyphenDuringParsing => _allowHyphenDuringParsing; + public bool AllowHyphenDuringParsing => _allowHyphenDuringParsing; private void InitializeInvariantAndNegativeSignFlags() { diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs index 0274b3ed1c14f8..fd96fb37f75954 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs @@ -15,9 +15,19 @@ namespace System.Numerics { - internal static class IeeeDecimalNumber + + +/* // Extension of NumberFormatInfo to bring in internal helpers, if needed + internal static class NumberFormatInfoExtension { + public static bool Extension_AllowHyphenDuringParsing(this NumberFormatInfo formatInfo) + { + return formatInfo.AllowHyphenDuringParsing; + } + }*/ + internal static class IeeeDecimalNumber + { // IeeeDecimalNumberBuffer internal const int Decimal32BufferLength = 0 + 1 + 1; // TODO: X for the longest input + 1 for rounding (+1 for the null terminator) @@ -402,7 +412,7 @@ private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, Nu { char* temp = p; ch = ++p < strEnd ? *p : '\0'; - if ((next = MatchChars(p, strEnd, info._positiveSign)) != null) + if ((next = MatchChars(p, strEnd, info.PositiveSign)) != null) { ch = (p = next) < strEnd ? *p : '\0'; } @@ -499,6 +509,18 @@ private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, Nu return false; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe char* MatchNegativeSignChars(char* p, char* pEnd, NumberFormatInfo info) + { + char* ret = MatchChars(p, pEnd, info.NegativeSign); + if (ret == null && info.AllowHyphenDuringParsing && p < pEnd && *p == '-') + { + ret = p + 1; + } + + return ret; + } + private static unsafe char* MatchChars(char* p, char* pEnd, string value) { Debug.Assert(p != null && pEnd != null && p <= pEnd && value != null); diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index e0d5586ee46573..095c4a3f0e0fce 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -8736,6 +8736,7 @@ public KoreanLunisolarCalendar() { } public sealed partial class NumberFormatInfo : System.ICloneable, System.IFormatProvider { public NumberFormatInfo() { } + public bool AllowHyphenDuringParsing { get { throw null; } } public int CurrencyDecimalDigits { get { throw null; } set { } } public string CurrencyDecimalSeparator { get { throw null; } set { } } public string CurrencyGroupSeparator { get { throw null; } set { } } From c327401407a39266afe6e3539cafdfa8f3743d72 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Mon, 19 Dec 2022 13:42:03 -0600 Subject: [PATCH 09/39] Fix csproj file to include IeeeDecimalNumber.cs --- .../System.Runtime.Numerics/src/System.Runtime.Numerics.csproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj b/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj index 23f147615ff226..be5c8efa5eab43 100644 --- a/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj +++ b/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj @@ -1,4 +1,4 @@ - + System.Numerics true @@ -6,6 +6,7 @@ + From faf39b4537606528fc945a43e537791c3570cf93 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Mon, 19 Dec 2022 13:59:38 -0600 Subject: [PATCH 10/39] remove methods --- .../src/System/Numerics/IeeeDecimalNumber.cs | 86 ++----------------- 1 file changed, 7 insertions(+), 79 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs index fd96fb37f75954..b145e607957ee0 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs @@ -231,6 +231,8 @@ internal static unsafe bool TryParseDecimal32(ReadOnlySpan value, NumberSt return true; } + internal static bool SpanStartsWith(ReadOnlySpan span, char c) => !span.IsEmpty && span[0] == c; + internal static unsafe bool TryStringToNumber(ReadOnlySpan value, NumberStyles styles, ref IeeeDecimalNumberBuffer number, NumberFormatInfo info) { Debug.Assert(info != null); @@ -249,6 +251,11 @@ internal static unsafe bool TryStringToNumber(ReadOnlySpan value, NumberSt return true; } + [MethodImpl(MethodImplOptions.NoInlining)] // rare slow path that shouldn't impact perf of the main use case + private static bool TrailingZeros(ReadOnlySpan value, int index) => + // For compatibility, we need to allow trailing zeros at the end of a number string + value.Slice(index).IndexOfAnyExcept('\0') < 0; + // This is almost a direct copy paste of the one in Number.Parsing.cs private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, NumberStyles styles, ref IeeeDecimalNumberBuffer number, NumberFormatInfo info) { @@ -578,85 +585,6 @@ internal static Decimal32 NumberToDecimal32(ref IeeeDecimalNumberBuffer number) return number.IsNegative ? Decimal32.Negate(result) : result; } - private static ushort NumberToDecimal32FloatingPointBits(ref IeeeDecimalNumberBuffer number, in FloatingPointInfo info) - { - Debug.Assert(info.DenormalMantissaBits == 10); - - Debug.Assert(number.GetDigitsPointer()[0] != '0'); - - Debug.Assert(number.Scale <= FloatingPointMaxExponent); - Debug.Assert(number.Scale >= FloatingPointMinExponent); - - Debug.Assert(number.DigitsCount != 0); - - // The input is of the form 0.Mantissa x 10^Exponent, where 'Mantissa' are - // the decimal digits of the mantissa and 'Exponent' is the decimal exponent. - // We decompose the mantissa into two parts: an integer part and a fractional - // part. If the exponent is positive, then the integer part consists of the - // first 'exponent' digits, or all present digits if there are fewer digits. - // If the exponent is zero or negative, then the integer part is empty. In - // either case, the remaining digits form the fractional part of the mantissa. - - uint totalDigits = (uint)(number.DigitsCount); - uint positiveExponent = (uint)(Math.Max(0, number.Scale)); - - uint integerDigitsPresent = Math.Min(positiveExponent, totalDigits); - uint fractionalDigitsPresent = totalDigits - integerDigitsPresent; - - int exponent = (int)(number.Scale - integerDigitsPresent - fractionalDigitsPresent); - int fastExponent = Math.Abs(exponent); - - // Above 19 digits, we rely on slow path - if (totalDigits <= 19) - { - byte* src = number.GetDigitsPointer(); - - // When the number of significant digits is less than or equal to MaxMantissaFastPath and the - // scale is less than or equal to MaxExponentFastPath, we can take some shortcuts and just rely - // on floating-point arithmetic to compute the correct result. This is - // because each floating-point precision values allows us to exactly represent - // different whole integers and certain powers of 10, depending on the underlying - // formats exact range. Additionally, IEEE operations dictate that the result is - // computed to the infinitely precise result and then rounded, which means that - // we can rely on it to produce the correct result when both inputs are exact. - // This is known as Clinger's fast path - - ulong mantissa = DigitsToUInt64(src, (int)(totalDigits)); - - if ((mantissa <= info.MaxMantissaFastPath) && (fastExponent <= info.MaxExponentFastPath)) - { - double mantissa_d = mantissa; - double scale = s_Pow10DoubleTable[fastExponent]; - - if (fractionalDigitsPresent != 0) - { - mantissa_d /= scale; - } - else - { - mantissa_d *= scale; - } - - return BitConverter.HalfToUInt16Bits((Half)(mantissa_d)); - } - - // Number Parsing at a Gigabyte per Second, Software: Practice and Experience 51(8), 2021 - // https://arxiv.org/abs/2101.11408 - (int Exponent, ulong Mantissa) am = ComputeFloat(exponent, mantissa, info); - - // If we called ComputeFloat and we have an invalid power of 2 (Exponent < 0), - // then we need to go the slow way around again. This is very uncommon. - if (am.Exponent > 0) - { - ulong word = am.Mantissa; - word |= (ulong)(uint)(am.Exponent) << info.DenormalMantissaBits; - return (ushort)word; - } - - } - return (ushort)NumberToFloatingPointBitsSlow(ref number, in info, positiveExponent, integerDigitsPresent, fractionalDigitsPresent); - } - internal enum ParsingStatus // No ParsingStatus.Overflow because these types can represent infinity { OK, From b6a36f8a01d9ec291ef1b4802c750d45c500bec2 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Mon, 19 Dec 2022 14:00:03 -0600 Subject: [PATCH 11/39] Start with Number.NumberToFloatingPointBits.cs copy --- .../System.Runtime.Numerics/src/System.Runtime.Numerics.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj b/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj index be5c8efa5eab43..dd51d48464adbe 100644 --- a/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj +++ b/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj @@ -7,6 +7,7 @@ + From 39cbf4105b593e1a39fa5209cb6af89d78e979aa Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Mon, 19 Dec 2022 14:58:18 -0600 Subject: [PATCH 12/39] Oops, forgot to add this file. This is the start of the work on the NumberToFloatingPointBits.cs copy --- ...DecimalNumber.NumberToFloatingPointBits.cs | 1683 +++++++++++++++++ 1 file changed, 1683 insertions(+) create mode 100644 src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.NumberToFloatingPointBits.cs diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.NumberToFloatingPointBits.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.NumberToFloatingPointBits.cs new file mode 100644 index 00000000000000..221734a983545c --- /dev/null +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.NumberToFloatingPointBits.cs @@ -0,0 +1,1683 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Buffers.Binary; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace System +{ + internal unsafe partial class IeeeDecimalNumber + { + public readonly struct FloatingPointInfo + { + public static readonly FloatingPointInfo Double = new FloatingPointInfo( + denormalMantissaBits: 52, + exponentBits: 11, + maxBinaryExponent: 1023, + exponentBias: 1023, + infinityBits: 0x7FF00000_00000000, + minFastFloatDecimalExponent: -342, + maxFastFloatDecimalExponent: 308, + infinityExponent: 0x7FF, + minExponentRoundToEven: -4, + maxExponentRoundToEven: 23, + maxExponentFastPath: 22 + ); + + public static readonly FloatingPointInfo Single = new FloatingPointInfo( + denormalMantissaBits: 23, + exponentBits: 8, + maxBinaryExponent: 127, + exponentBias: 127, + infinityBits: 0x7F800000, + minFastFloatDecimalExponent: -65, + maxFastFloatDecimalExponent: 38, + infinityExponent: 0xFF, + minExponentRoundToEven: -17, + maxExponentRoundToEven: 10, + maxExponentFastPath: 10 + ); + public static readonly FloatingPointInfo Half = new FloatingPointInfo( + denormalMantissaBits: 10, + exponentBits: 5, + maxBinaryExponent: 15, + exponentBias: 15, + infinityBits: 0x7C00, + minFastFloatDecimalExponent: -8, + maxFastFloatDecimalExponent: 4, + infinityExponent: 0x1F, + minExponentRoundToEven: -21, + maxExponentRoundToEven: 5, + maxExponentFastPath: 4 + ); + + public ulong ZeroBits { get; } + public ulong InfinityBits { get; } + + public ulong NormalMantissaMask { get; } + public ulong DenormalMantissaMask { get; } + + public int MinBinaryExponent { get; } + public int MaxBinaryExponent { get; } + + public int ExponentBias { get; } + public int OverflowDecimalExponent { get; } + + public ushort NormalMantissaBits { get; } + public ushort DenormalMantissaBits { get; } + + public int MinFastFloatDecimalExponent { get; } + public int InfinityExponent { get; } + public int MinExponentRoundToEven { get; } + public int MaxExponentRoundToEven { get; } + + public int MaxExponentFastPath { get; } + + public int MaxFastFloatDecimalExponent { get; } + public ulong MaxMantissaFastPath { get => 2UL << DenormalMantissaBits; } + public ushort ExponentBits { get; } + + public FloatingPointInfo(ushort denormalMantissaBits, ushort exponentBits, int maxBinaryExponent, int exponentBias, ulong infinityBits, int minFastFloatDecimalExponent, int maxFastFloatDecimalExponent, int infinityExponent, int minExponentRoundToEven, int maxExponentRoundToEven, int maxExponentFastPath) + { + ExponentBits = exponentBits; + + DenormalMantissaBits = denormalMantissaBits; + NormalMantissaBits = (ushort)(denormalMantissaBits + 1); // we get an extra (hidden) bit for normal mantissas + + OverflowDecimalExponent = (maxBinaryExponent + 2 * NormalMantissaBits) / 3; + ExponentBias = exponentBias; + + MaxBinaryExponent = maxBinaryExponent; + MinBinaryExponent = 1 - maxBinaryExponent; + + DenormalMantissaMask = (1UL << denormalMantissaBits) - 1; + NormalMantissaMask = (1UL << NormalMantissaBits) - 1; + + InfinityBits = infinityBits; + ZeroBits = 0; + + MaxFastFloatDecimalExponent = maxFastFloatDecimalExponent; + MinFastFloatDecimalExponent = minFastFloatDecimalExponent; + + InfinityExponent = infinityExponent; + + MinExponentRoundToEven = minExponentRoundToEven; + MaxExponentRoundToEven = maxExponentRoundToEven; + + MaxExponentFastPath = maxExponentFastPath; + } + } + + private static readonly double[] s_Pow10DoubleTable = { + 1e0, // 10^0 + 1e1, // 10^1 + 1e2, // 10^2 + 1e3, // 10^3 + 1e4, // 10^4 + 1e5, // 10^5 + 1e6, // 10^6 + 1e7, // 10^7 + 1e8, // 10^8 + 1e9, // 10^9 + 1e10, // 10^10 + 1e11, // 10^11 + 1e12, // 10^12 + 1e13, // 10^13 + 1e14, // 10^14 + 1e15, // 10^15 + 1e16, // 10^16 + 1e17, // 10^17 + 1e18, // 10^18 + 1e19, // 10^19 + 1e20, // 10^20 + 1e21, // 10^21 + 1e22, // 10^22 + }; + + /// + /// Normalized 128 bits values for powers of 5^q for q in range [-342, 308] + /// stored as 2 64-bits integers for convenience + /// + private static readonly ulong[] s_Pow5128Table = { + 0xeef453d6923bd65a, 0x113faa2906a13b3f, + 0x9558b4661b6565f8, 0x4ac7ca59a424c507, + 0xbaaee17fa23ebf76, 0x5d79bcf00d2df649, + 0xe95a99df8ace6f53, 0xf4d82c2c107973dc, + 0x91d8a02bb6c10594, 0x79071b9b8a4be869, + 0xb64ec836a47146f9, 0x9748e2826cdee284, + 0xe3e27a444d8d98b7, 0xfd1b1b2308169b25, + 0x8e6d8c6ab0787f72, 0xfe30f0f5e50e20f7, + 0xb208ef855c969f4f, 0xbdbd2d335e51a935, + 0xde8b2b66b3bc4723, 0xad2c788035e61382, + 0x8b16fb203055ac76, 0x4c3bcb5021afcc31, + 0xaddcb9e83c6b1793, 0xdf4abe242a1bbf3d, + 0xd953e8624b85dd78, 0xd71d6dad34a2af0d, + 0x87d4713d6f33aa6b, 0x8672648c40e5ad68, + 0xa9c98d8ccb009506, 0x680efdaf511f18c2, + 0xd43bf0effdc0ba48, 0x212bd1b2566def2, + 0x84a57695fe98746d, 0x14bb630f7604b57, + 0xa5ced43b7e3e9188, 0x419ea3bd35385e2d, + 0xcf42894a5dce35ea, 0x52064cac828675b9, + 0x818995ce7aa0e1b2, 0x7343efebd1940993, + 0xa1ebfb4219491a1f, 0x1014ebe6c5f90bf8, + 0xca66fa129f9b60a6, 0xd41a26e077774ef6, + 0xfd00b897478238d0, 0x8920b098955522b4, + 0x9e20735e8cb16382, 0x55b46e5f5d5535b0, + 0xc5a890362fddbc62, 0xeb2189f734aa831d, + 0xf712b443bbd52b7b, 0xa5e9ec7501d523e4, + 0x9a6bb0aa55653b2d, 0x47b233c92125366e, + 0xc1069cd4eabe89f8, 0x999ec0bb696e840a, + 0xf148440a256e2c76, 0xc00670ea43ca250d, + 0x96cd2a865764dbca, 0x380406926a5e5728, + 0xbc807527ed3e12bc, 0xc605083704f5ecf2, + 0xeba09271e88d976b, 0xf7864a44c633682e, + 0x93445b8731587ea3, 0x7ab3ee6afbe0211d, + 0xb8157268fdae9e4c, 0x5960ea05bad82964, + 0xe61acf033d1a45df, 0x6fb92487298e33bd, + 0x8fd0c16206306bab, 0xa5d3b6d479f8e056, + 0xb3c4f1ba87bc8696, 0x8f48a4899877186c, + 0xe0b62e2929aba83c, 0x331acdabfe94de87, + 0x8c71dcd9ba0b4925, 0x9ff0c08b7f1d0b14, + 0xaf8e5410288e1b6f, 0x7ecf0ae5ee44dd9, + 0xdb71e91432b1a24a, 0xc9e82cd9f69d6150, + 0x892731ac9faf056e, 0xbe311c083a225cd2, + 0xab70fe17c79ac6ca, 0x6dbd630a48aaf406, + 0xd64d3d9db981787d, 0x92cbbccdad5b108, + 0x85f0468293f0eb4e, 0x25bbf56008c58ea5, + 0xa76c582338ed2621, 0xaf2af2b80af6f24e, + 0xd1476e2c07286faa, 0x1af5af660db4aee1, + 0x82cca4db847945ca, 0x50d98d9fc890ed4d, + 0xa37fce126597973c, 0xe50ff107bab528a0, + 0xcc5fc196fefd7d0c, 0x1e53ed49a96272c8, + 0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7a, + 0x9faacf3df73609b1, 0x77b191618c54e9ac, + 0xc795830d75038c1d, 0xd59df5b9ef6a2417, + 0xf97ae3d0d2446f25, 0x4b0573286b44ad1d, + 0x9becce62836ac577, 0x4ee367f9430aec32, + 0xc2e801fb244576d5, 0x229c41f793cda73f, + 0xf3a20279ed56d48a, 0x6b43527578c1110f, + 0x9845418c345644d6, 0x830a13896b78aaa9, + 0xbe5691ef416bd60c, 0x23cc986bc656d553, + 0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa8, + 0x94b3a202eb1c3f39, 0x7bf7d71432f3d6a9, + 0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc53, + 0xe858ad248f5c22c9, 0xd1b3400f8f9cff68, + 0x91376c36d99995be, 0x23100809b9c21fa1, + 0xb58547448ffffb2d, 0xabd40a0c2832a78a, + 0xe2e69915b3fff9f9, 0x16c90c8f323f516c, + 0x8dd01fad907ffc3b, 0xae3da7d97f6792e3, + 0xb1442798f49ffb4a, 0x99cd11cfdf41779c, + 0xdd95317f31c7fa1d, 0x40405643d711d583, + 0x8a7d3eef7f1cfc52, 0x482835ea666b2572, + 0xad1c8eab5ee43b66, 0xda3243650005eecf, + 0xd863b256369d4a40, 0x90bed43e40076a82, + 0x873e4f75e2224e68, 0x5a7744a6e804a291, + 0xa90de3535aaae202, 0x711515d0a205cb36, + 0xd3515c2831559a83, 0xd5a5b44ca873e03, + 0x8412d9991ed58091, 0xe858790afe9486c2, + 0xa5178fff668ae0b6, 0x626e974dbe39a872, + 0xce5d73ff402d98e3, 0xfb0a3d212dc8128f, + 0x80fa687f881c7f8e, 0x7ce66634bc9d0b99, + 0xa139029f6a239f72, 0x1c1fffc1ebc44e80, + 0xc987434744ac874e, 0xa327ffb266b56220, + 0xfbe9141915d7a922, 0x4bf1ff9f0062baa8, + 0x9d71ac8fada6c9b5, 0x6f773fc3603db4a9, + 0xc4ce17b399107c22, 0xcb550fb4384d21d3, + 0xf6019da07f549b2b, 0x7e2a53a146606a48, + 0x99c102844f94e0fb, 0x2eda7444cbfc426d, + 0xc0314325637a1939, 0xfa911155fefb5308, + 0xf03d93eebc589f88, 0x793555ab7eba27ca, + 0x96267c7535b763b5, 0x4bc1558b2f3458de, + 0xbbb01b9283253ca2, 0x9eb1aaedfb016f16, + 0xea9c227723ee8bcb, 0x465e15a979c1cadc, + 0x92a1958a7675175f, 0xbfacd89ec191ec9, + 0xb749faed14125d36, 0xcef980ec671f667b, + 0xe51c79a85916f484, 0x82b7e12780e7401a, + 0x8f31cc0937ae58d2, 0xd1b2ecb8b0908810, + 0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa15, + 0xdfbdcece67006ac9, 0x67a791e093e1d49a, + 0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e0, + 0xaecc49914078536d, 0x58fae9f773886e18, + 0xda7f5bf590966848, 0xaf39a475506a899e, + 0x888f99797a5e012d, 0x6d8406c952429603, + 0xaab37fd7d8f58178, 0xc8e5087ba6d33b83, + 0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a64, + 0x855c3be0a17fcd26, 0x5cf2eea09a55067f, + 0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481e, + 0xd0601d8efc57b08b, 0xf13b94daf124da26, + 0x823c12795db6ce57, 0x76c53d08d6b70858, + 0xa2cb1717b52481ed, 0x54768c4b0c64ca6e, + 0xcb7ddcdda26da268, 0xa9942f5dcf7dfd09, + 0xfe5d54150b090b02, 0xd3f93b35435d7c4c, + 0x9efa548d26e5a6e1, 0xc47bc5014a1a6daf, + 0xc6b8e9b0709f109a, 0x359ab6419ca1091b, + 0xf867241c8cc6d4c0, 0xc30163d203c94b62, + 0x9b407691d7fc44f8, 0x79e0de63425dcf1d, + 0xc21094364dfb5636, 0x985915fc12f542e4, + 0xf294b943e17a2bc4, 0x3e6f5b7b17b2939d, + 0x979cf3ca6cec5b5a, 0xa705992ceecf9c42, + 0xbd8430bd08277231, 0x50c6ff782a838353, + 0xece53cec4a314ebd, 0xa4f8bf5635246428, + 0x940f4613ae5ed136, 0x871b7795e136be99, + 0xb913179899f68584, 0x28e2557b59846e3f, + 0xe757dd7ec07426e5, 0x331aeada2fe589cf, + 0x9096ea6f3848984f, 0x3ff0d2c85def7621, + 0xb4bca50b065abe63, 0xfed077a756b53a9, + 0xe1ebce4dc7f16dfb, 0xd3e8495912c62894, + 0x8d3360f09cf6e4bd, 0x64712dd7abbbd95c, + 0xb080392cc4349dec, 0xbd8d794d96aacfb3, + 0xdca04777f541c567, 0xecf0d7a0fc5583a0, + 0x89e42caaf9491b60, 0xf41686c49db57244, + 0xac5d37d5b79b6239, 0x311c2875c522ced5, + 0xd77485cb25823ac7, 0x7d633293366b828b, + 0x86a8d39ef77164bc, 0xae5dff9c02033197, + 0xa8530886b54dbdeb, 0xd9f57f830283fdfc, + 0xd267caa862a12d66, 0xd072df63c324fd7b, + 0x8380dea93da4bc60, 0x4247cb9e59f71e6d, + 0xa46116538d0deb78, 0x52d9be85f074e608, + 0xcd795be870516656, 0x67902e276c921f8b, + 0x806bd9714632dff6, 0xba1cd8a3db53b6, + 0xa086cfcd97bf97f3, 0x80e8a40eccd228a4, + 0xc8a883c0fdaf7df0, 0x6122cd128006b2cd, + 0xfad2a4b13d1b5d6c, 0x796b805720085f81, + 0x9cc3a6eec6311a63, 0xcbe3303674053bb0, + 0xc3f490aa77bd60fc, 0xbedbfc4411068a9c, + 0xf4f1b4d515acb93b, 0xee92fb5515482d44, + 0x991711052d8bf3c5, 0x751bdd152d4d1c4a, + 0xbf5cd54678eef0b6, 0xd262d45a78a0635d, + 0xef340a98172aace4, 0x86fb897116c87c34, + 0x9580869f0e7aac0e, 0xd45d35e6ae3d4da0, + 0xbae0a846d2195712, 0x8974836059cca109, + 0xe998d258869facd7, 0x2bd1a438703fc94b, + 0x91ff83775423cc06, 0x7b6306a34627ddcf, + 0xb67f6455292cbf08, 0x1a3bc84c17b1d542, + 0xe41f3d6a7377eeca, 0x20caba5f1d9e4a93, + 0x8e938662882af53e, 0x547eb47b7282ee9c, + 0xb23867fb2a35b28d, 0xe99e619a4f23aa43, + 0xdec681f9f4c31f31, 0x6405fa00e2ec94d4, + 0x8b3c113c38f9f37e, 0xde83bc408dd3dd04, + 0xae0b158b4738705e, 0x9624ab50b148d445, + 0xd98ddaee19068c76, 0x3badd624dd9b0957, + 0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d6, + 0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4c, + 0xd47487cc8470652b, 0x7647c3200069671f, + 0x84c8d4dfd2c63f3b, 0x29ecd9f40041e073, + 0xa5fb0a17c777cf09, 0xf468107100525890, + 0xcf79cc9db955c2cc, 0x7182148d4066eeb4, + 0x81ac1fe293d599bf, 0xc6f14cd848405530, + 0xa21727db38cb002f, 0xb8ada00e5a506a7c, + 0xca9cf1d206fdc03b, 0xa6d90811f0e4851c, + 0xfd442e4688bd304a, 0x908f4a166d1da663, + 0x9e4a9cec15763e2e, 0x9a598e4e043287fe, + 0xc5dd44271ad3cdba, 0x40eff1e1853f29fd, + 0xf7549530e188c128, 0xd12bee59e68ef47c, + 0x9a94dd3e8cf578b9, 0x82bb74f8301958ce, + 0xc13a148e3032d6e7, 0xe36a52363c1faf01, + 0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac1, + 0x96f5600f15a7b7e5, 0x29ab103a5ef8c0b9, + 0xbcb2b812db11a5de, 0x7415d448f6b6f0e7, + 0xebdf661791d60f56, 0x111b495b3464ad21, + 0x936b9fcebb25c995, 0xcab10dd900beec34, + 0xb84687c269ef3bfb, 0x3d5d514f40eea742, + 0xe65829b3046b0afa, 0xcb4a5a3112a5112, + 0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ab, + 0xb3f4e093db73a093, 0x59ed216765690f56, + 0xe0f218b8d25088b8, 0x306869c13ec3532c, + 0x8c974f7383725573, 0x1e414218c73a13fb, + 0xafbd2350644eeacf, 0xe5d1929ef90898fa, + 0xdbac6c247d62a583, 0xdf45f746b74abf39, + 0x894bc396ce5da772, 0x6b8bba8c328eb783, + 0xab9eb47c81f5114f, 0x66ea92f3f326564, + 0xd686619ba27255a2, 0xc80a537b0efefebd, + 0x8613fd0145877585, 0xbd06742ce95f5f36, + 0xa798fc4196e952e7, 0x2c48113823b73704, + 0xd17f3b51fca3a7a0, 0xf75a15862ca504c5, + 0x82ef85133de648c4, 0x9a984d73dbe722fb, + 0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebba, + 0xcc963fee10b7d1b3, 0x318df905079926a8, + 0xffbbcfe994e5c61f, 0xfdf17746497f7052, + 0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa633, + 0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc0, + 0xf9bd690a1b68637b, 0x3dfdce7aa3c673b0, + 0x9c1661a651213e2d, 0x6bea10ca65c084e, + 0xc31bfa0fe5698db8, 0x486e494fcff30a62, + 0xf3e2f893dec3f126, 0x5a89dba3c3efccfa, + 0x986ddb5c6b3a76b7, 0xf89629465a75e01c, + 0xbe89523386091465, 0xf6bbb397f1135823, + 0xee2ba6c0678b597f, 0x746aa07ded582e2c, + 0x94db483840b717ef, 0xa8c2a44eb4571cdc, + 0xba121a4650e4ddeb, 0x92f34d62616ce413, + 0xe896a0d7e51e1566, 0x77b020baf9c81d17, + 0x915e2486ef32cd60, 0xace1474dc1d122e, + 0xb5b5ada8aaff80b8, 0xd819992132456ba, + 0xe3231912d5bf60e6, 0x10e1fff697ed6c69, + 0x8df5efabc5979c8f, 0xca8d3ffa1ef463c1, + 0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb2, + 0xddd0467c64bce4a0, 0xac7cb3f6d05ddbde, + 0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96b, + 0xad4ab7112eb3929d, 0x86c16c98d2c953c6, + 0xd89d64d57a607744, 0xe871c7bf077ba8b7, + 0x87625f056c7c4a8b, 0x11471cd764ad4972, + 0xa93af6c6c79b5d2d, 0xd598e40d3dd89bcf, + 0xd389b47879823479, 0x4aff1d108d4ec2c3, + 0x843610cb4bf160cb, 0xcedf722a585139ba, + 0xa54394fe1eedb8fe, 0xc2974eb4ee658828, + 0xce947a3da6a9273e, 0x733d226229feea32, + 0x811ccc668829b887, 0x806357d5a3f525f, + 0xa163ff802a3426a8, 0xca07c2dcb0cf26f7, + 0xc9bcff6034c13052, 0xfc89b393dd02f0b5, + 0xfc2c3f3841f17c67, 0xbbac2078d443ace2, + 0x9d9ba7832936edc0, 0xd54b944b84aa4c0d, + 0xc5029163f384a931, 0xa9e795e65d4df11, + 0xf64335bcf065d37d, 0x4d4617b5ff4a16d5, + 0x99ea0196163fa42e, 0x504bced1bf8e4e45, + 0xc06481fb9bcf8d39, 0xe45ec2862f71e1d6, + 0xf07da27a82c37088, 0x5d767327bb4e5a4c, + 0x964e858c91ba2655, 0x3a6a07f8d510f86f, + 0xbbe226efb628afea, 0x890489f70a55368b, + 0xeadab0aba3b2dbe5, 0x2b45ac74ccea842e, + 0x92c8ae6b464fc96f, 0x3b0b8bc90012929d, + 0xb77ada0617e3bbcb, 0x9ce6ebb40173744, + 0xe55990879ddcaabd, 0xcc420a6a101d0515, + 0x8f57fa54c2a9eab6, 0x9fa946824a12232d, + 0xb32df8e9f3546564, 0x47939822dc96abf9, + 0xdff9772470297ebd, 0x59787e2b93bc56f7, + 0x8bfbea76c619ef36, 0x57eb4edb3c55b65a, + 0xaefae51477a06b03, 0xede622920b6b23f1, + 0xdab99e59958885c4, 0xe95fab368e45eced, + 0x88b402f7fd75539b, 0x11dbcb0218ebb414, + 0xaae103b5fcd2a881, 0xd652bdc29f26a119, + 0xd59944a37c0752a2, 0x4be76d3346f0495f, + 0x857fcae62d8493a5, 0x6f70a4400c562ddb, + 0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb952, + 0xd097ad07a71f26b2, 0x7e2000a41346a7a7, + 0x825ecc24c873782f, 0x8ed400668c0c28c8, + 0xa2f67f2dfa90563b, 0x728900802f0f32fa, + 0xcbb41ef979346bca, 0x4f2b40a03ad2ffb9, + 0xfea126b7d78186bc, 0xe2f610c84987bfa8, + 0x9f24b832e6b0f436, 0xdd9ca7d2df4d7c9, + 0xc6ede63fa05d3143, 0x91503d1c79720dbb, + 0xf8a95fcf88747d94, 0x75a44c6397ce912a, + 0x9b69dbe1b548ce7c, 0xc986afbe3ee11aba, + 0xc24452da229b021b, 0xfbe85badce996168, + 0xf2d56790ab41c2a2, 0xfae27299423fb9c3, + 0x97c560ba6b0919a5, 0xdccd879fc967d41a, + 0xbdb6b8e905cb600f, 0x5400e987bbc1c920, + 0xed246723473e3813, 0x290123e9aab23b68, + 0x9436c0760c86e30b, 0xf9a0b6720aaf6521, + 0xb94470938fa89bce, 0xf808e40e8d5b3e69, + 0xe7958cb87392c2c2, 0xb60b1d1230b20e04, + 0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c2, + 0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af3, + 0xe2280b6c20dd5232, 0x25c6da63c38de1b0, + 0x8d590723948a535f, 0x579c487e5a38ad0e, + 0xb0af48ec79ace837, 0x2d835a9df0c6d851, + 0xdcdb1b2798182244, 0xf8e431456cf88e65, + 0x8a08f0f8bf0f156b, 0x1b8e9ecb641b58ff, + 0xac8b2d36eed2dac5, 0xe272467e3d222f3f, + 0xd7adf884aa879177, 0x5b0ed81dcc6abb0f, + 0x86ccbb52ea94baea, 0x98e947129fc2b4e9, + 0xa87fea27a539e9a5, 0x3f2398d747b36224, + 0xd29fe4b18e88640e, 0x8eec7f0d19a03aad, + 0x83a3eeeef9153e89, 0x1953cf68300424ac, + 0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd7, + 0xcdb02555653131b6, 0x3792f412cb06794d, + 0x808e17555f3ebf11, 0xe2bbd88bbee40bd0, + 0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec4, + 0xc8de047564d20a8b, 0xf245825a5a445275, + 0xfb158592be068d2e, 0xeed6e2f0f0d56712, + 0x9ced737bb6c4183d, 0x55464dd69685606b, + 0xc428d05aa4751e4c, 0xaa97e14c3c26b886, + 0xf53304714d9265df, 0xd53dd99f4b3066a8, + 0x993fe2c6d07b7fab, 0xe546a8038efe4029, + 0xbf8fdb78849a5f96, 0xde98520472bdd033, + 0xef73d256a5c0f77c, 0x963e66858f6d4440, + 0x95a8637627989aad, 0xdde7001379a44aa8, + 0xbb127c53b17ec159, 0x5560c018580d5d52, + 0xe9d71b689dde71af, 0xaab8f01e6e10b4a6, + 0x9226712162ab070d, 0xcab3961304ca70e8, + 0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d22, + 0xe45c10c42a2b3b05, 0x8cb89a7db77c506a, + 0x8eb98a7a9a5b04e3, 0x77f3608e92adb242, + 0xb267ed1940f1c61c, 0x55f038b237591ed3, + 0xdf01e85f912e37a3, 0x6b6c46dec52f6688, + 0x8b61313bbabce2c6, 0x2323ac4b3b3da015, + 0xae397d8aa96c1b77, 0xabec975e0a0d081a, + 0xd9c7dced53c72255, 0x96e7bd358c904a21, + 0x881cea14545c7575, 0x7e50d64177da2e54, + 0xaa242499697392d2, 0xdde50bd1d5d0b9e9, + 0xd4ad2dbfc3d07787, 0x955e4ec64b44e864, + 0x84ec3c97da624ab4, 0xbd5af13bef0b113e, + 0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58e, + 0xcfb11ead453994ba, 0x67de18eda5814af2, + 0x81ceb32c4b43fcf4, 0x80eacf948770ced7, + 0xa2425ff75e14fc31, 0xa1258379a94d028d, + 0xcad2f7f5359a3b3e, 0x96ee45813a04330, + 0xfd87b5f28300ca0d, 0x8bca9d6e188853fc, + 0x9e74d1b791e07e48, 0x775ea264cf55347e, + 0xc612062576589dda, 0x95364afe032a819e, + 0xf79687aed3eec551, 0x3a83ddbd83f52205, + 0x9abe14cd44753b52, 0xc4926a9672793543, + 0xc16d9a0095928a27, 0x75b7053c0f178294, + 0xf1c90080baf72cb1, 0x5324c68b12dd6339, + 0x971da05074da7bee, 0xd3f6fc16ebca5e04, + 0xbce5086492111aea, 0x88f4bb1ca6bcf585, + 0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6, + 0x9392ee8e921d5d07, 0x3aff322e62439fd0, + 0xb877aa3236a4b449, 0x9befeb9fad487c3, + 0xe69594bec44de15b, 0x4c2ebe687989a9b4, + 0x901d7cf73ab0acd9, 0xf9d37014bf60a11, + 0xb424dc35095cd80f, 0x538484c19ef38c95, + 0xe12e13424bb40e13, 0x2865a5f206b06fba, + 0x8cbccc096f5088cb, 0xf93f87b7442e45d4, + 0xafebff0bcb24aafe, 0xf78f69a51539d749, + 0xdbe6fecebdedd5be, 0xb573440e5a884d1c, + 0x89705f4136b4a597, 0x31680a88f8953031, + 0xabcc77118461cefc, 0xfdc20d2b36ba7c3e, + 0xd6bf94d5e57a42bc, 0x3d32907604691b4d, + 0x8637bd05af6c69b5, 0xa63f9a49c2c1b110, + 0xa7c5ac471b478423, 0xfcf80dc33721d54, + 0xd1b71758e219652b, 0xd3c36113404ea4a9, + 0x83126e978d4fdf3b, 0x645a1cac083126ea, + 0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4, + 0xcccccccccccccccc, 0xcccccccccccccccd, + 0x8000000000000000, 0x0, + 0xa000000000000000, 0x0, + 0xc800000000000000, 0x0, + 0xfa00000000000000, 0x0, + 0x9c40000000000000, 0x0, + 0xc350000000000000, 0x0, + 0xf424000000000000, 0x0, + 0x9896800000000000, 0x0, + 0xbebc200000000000, 0x0, + 0xee6b280000000000, 0x0, + 0x9502f90000000000, 0x0, + 0xba43b74000000000, 0x0, + 0xe8d4a51000000000, 0x0, + 0x9184e72a00000000, 0x0, + 0xb5e620f480000000, 0x0, + 0xe35fa931a0000000, 0x0, + 0x8e1bc9bf04000000, 0x0, + 0xb1a2bc2ec5000000, 0x0, + 0xde0b6b3a76400000, 0x0, + 0x8ac7230489e80000, 0x0, + 0xad78ebc5ac620000, 0x0, + 0xd8d726b7177a8000, 0x0, + 0x878678326eac9000, 0x0, + 0xa968163f0a57b400, 0x0, + 0xd3c21bcecceda100, 0x0, + 0x84595161401484a0, 0x0, + 0xa56fa5b99019a5c8, 0x0, + 0xcecb8f27f4200f3a, 0x0, + 0x813f3978f8940984, 0x4000000000000000, + 0xa18f07d736b90be5, 0x5000000000000000, + 0xc9f2c9cd04674ede, 0xa400000000000000, + 0xfc6f7c4045812296, 0x4d00000000000000, + 0x9dc5ada82b70b59d, 0xf020000000000000, + 0xc5371912364ce305, 0x6c28000000000000, + 0xf684df56c3e01bc6, 0xc732000000000000, + 0x9a130b963a6c115c, 0x3c7f400000000000, + 0xc097ce7bc90715b3, 0x4b9f100000000000, + 0xf0bdc21abb48db20, 0x1e86d40000000000, + 0x96769950b50d88f4, 0x1314448000000000, + 0xbc143fa4e250eb31, 0x17d955a000000000, + 0xeb194f8e1ae525fd, 0x5dcfab0800000000, + 0x92efd1b8d0cf37be, 0x5aa1cae500000000, + 0xb7abc627050305ad, 0xf14a3d9e40000000, + 0xe596b7b0c643c719, 0x6d9ccd05d0000000, + 0x8f7e32ce7bea5c6f, 0xe4820023a2000000, + 0xb35dbf821ae4f38b, 0xdda2802c8a800000, + 0xe0352f62a19e306e, 0xd50b2037ad200000, + 0x8c213d9da502de45, 0x4526f422cc340000, + 0xaf298d050e4395d6, 0x9670b12b7f410000, + 0xdaf3f04651d47b4c, 0x3c0cdd765f114000, + 0x88d8762bf324cd0f, 0xa5880a69fb6ac800, + 0xab0e93b6efee0053, 0x8eea0d047a457a00, + 0xd5d238a4abe98068, 0x72a4904598d6d880, + 0x85a36366eb71f041, 0x47a6da2b7f864750, + 0xa70c3c40a64e6c51, 0x999090b65f67d924, + 0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d, + 0x82818f1281ed449f, 0xbff8f10e7a8921a4, + 0xa321f2d7226895c7, 0xaff72d52192b6a0d, + 0xcbea6f8ceb02bb39, 0x9bf4f8a69f764490, + 0xfee50b7025c36a08, 0x2f236d04753d5b4, + 0x9f4f2726179a2245, 0x1d762422c946590, + 0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef5, + 0xf8ebad2b84e0d58b, 0xd2e0898765a7deb2, + 0x9b934c3b330c8577, 0x63cc55f49f88eb2f, + 0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fb, + 0xf316271c7fc3908a, 0x8bef464e3945ef7a, + 0x97edd871cfda3a56, 0x97758bf0e3cbb5ac, + 0xbde94e8e43d0c8ec, 0x3d52eeed1cbea317, + 0xed63a231d4c4fb27, 0x4ca7aaa863ee4bdd, + 0x945e455f24fb1cf8, 0x8fe8caa93e74ef6a, + 0xb975d6b6ee39e436, 0xb3e2fd538e122b44, + 0xe7d34c64a9c85d44, 0x60dbbca87196b616, + 0x90e40fbeea1d3a4a, 0xbc8955e946fe31cd, + 0xb51d13aea4a488dd, 0x6babab6398bdbe41, + 0xe264589a4dcdab14, 0xc696963c7eed2dd1, + 0x8d7eb76070a08aec, 0xfc1e1de5cf543ca2, + 0xb0de65388cc8ada8, 0x3b25a55f43294bcb, + 0xdd15fe86affad912, 0x49ef0eb713f39ebe, + 0x8a2dbf142dfcc7ab, 0x6e3569326c784337, + 0xacb92ed9397bf996, 0x49c2c37f07965404, + 0xd7e77a8f87daf7fb, 0xdc33745ec97be906, + 0x86f0ac99b4e8dafd, 0x69a028bb3ded71a3, + 0xa8acd7c0222311bc, 0xc40832ea0d68ce0c, + 0xd2d80db02aabd62b, 0xf50a3fa490c30190, + 0x83c7088e1aab65db, 0x792667c6da79e0fa, + 0xa4b8cab1a1563f52, 0x577001b891185938, + 0xcde6fd5e09abcf26, 0xed4c0226b55e6f86, + 0x80b05e5ac60b6178, 0x544f8158315b05b4, + 0xa0dc75f1778e39d6, 0x696361ae3db1c721, + 0xc913936dd571c84c, 0x3bc3a19cd1e38e9, + 0xfb5878494ace3a5f, 0x4ab48a04065c723, + 0x9d174b2dcec0e47b, 0x62eb0d64283f9c76, + 0xc45d1df942711d9a, 0x3ba5d0bd324f8394, + 0xf5746577930d6500, 0xca8f44ec7ee36479, + 0x9968bf6abbe85f20, 0x7e998b13cf4e1ecb, + 0xbfc2ef456ae276e8, 0x9e3fedd8c321a67e, + 0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101e, + 0x95d04aee3b80ece5, 0xbba1f1d158724a12, + 0xbb445da9ca61281f, 0x2a8a6e45ae8edc97, + 0xea1575143cf97226, 0xf52d09d71a3293bd, + 0x924d692ca61be758, 0x593c2626705f9c56, + 0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836c, + 0xe498f455c38b997a, 0xb6dfb9c0f956447, + 0x8edf98b59a373fec, 0x4724bd4189bd5eac, + 0xb2977ee300c50fe7, 0x58edec91ec2cb657, + 0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ed, + 0x8b865b215899f46c, 0xbd79e0d20082ee74, + 0xae67f1e9aec07187, 0xecd8590680a3aa11, + 0xda01ee641a708de9, 0xe80e6f4820cc9495, + 0x884134fe908658b2, 0x3109058d147fdcdd, + 0xaa51823e34a7eede, 0xbd4b46f0599fd415, + 0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91a, + 0x850fadc09923329e, 0x3e2cf6bc604ddb0, + 0xa6539930bf6bff45, 0x84db8346b786151c, + 0xcfe87f7cef46ff16, 0xe612641865679a63, + 0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07e, + 0xa26da3999aef7749, 0xe3be5e330f38f09d, + 0xcb090c8001ab551c, 0x5cadf5bfd3072cc5, + 0xfdcb4fa002162a63, 0x73d9732fc7c8f7f6, + 0x9e9f11c4014dda7e, 0x2867e7fddcdd9afa, + 0xc646d63501a1511d, 0xb281e1fd541501b8, + 0xf7d88bc24209a565, 0x1f225a7ca91a4226, + 0x9ae757596946075f, 0x3375788de9b06958, + 0xc1a12d2fc3978937, 0x52d6b1641c83ae, + 0xf209787bb47d6b84, 0xc0678c5dbd23a49a, + 0x9745eb4d50ce6332, 0xf840b7ba963646e0, + 0xbd176620a501fbff, 0xb650e5a93bc3d898, + 0xec5d3fa8ce427aff, 0xa3e51f138ab4cebe, + 0x93ba47c980e98cdf, 0xc66f336c36b10137, + 0xb8a8d9bbe123f017, 0xb80b0047445d4184, + 0xe6d3102ad96cec1d, 0xa60dc059157491e5, + 0x9043ea1ac7e41392, 0x87c89837ad68db2f, + 0xb454e4a179dd1877, 0x29babe4598c311fb, + 0xe16a1dc9d8545e94, 0xf4296dd6fef3d67a, + 0x8ce2529e2734bb1d, 0x1899e4a65f58660c, + 0xb01ae745b101e9e4, 0x5ec05dcff72e7f8f, + 0xdc21a1171d42645d, 0x76707543f4fa1f73, + 0x899504ae72497eba, 0x6a06494a791c53a8, + 0xabfa45da0edbde69, 0x487db9d17636892, + 0xd6f8d7509292d603, 0x45a9d2845d3c42b6, + 0x865b86925b9bc5c2, 0xb8a2392ba45a9b2, + 0xa7f26836f282b732, 0x8e6cac7768d7141e, + 0xd1ef0244af2364ff, 0x3207d795430cd926, + 0x8335616aed761f1f, 0x7f44e6bd49e807b8, + 0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a6, + 0xcd036837130890a1, 0x36dba887c37a8c0f, + 0x802221226be55a64, 0xc2494954da2c9789, + 0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6c, + 0xc83553c5c8965d3d, 0x6f92829494e5acc7, + 0xfa42a8b73abbf48c, 0xcb772339ba1f17f9, + 0x9c69a97284b578d7, 0xff2a760414536efb, + 0xc38413cf25e2d70d, 0xfef5138519684aba, + 0xf46518c2ef5b8cd1, 0x7eb258665fc25d69, + 0x98bf2f79d5993802, 0xef2f773ffbd97a61, + 0xbeeefb584aff8603, 0xaafb550ffacfd8fa, + 0xeeaaba2e5dbf6784, 0x95ba2a53f983cf38, + 0x952ab45cfa97a0b2, 0xdd945a747bf26183, + 0xba756174393d88df, 0x94f971119aeef9e4, + 0xe912b9d1478ceb17, 0x7a37cd5601aab85d, + 0x91abb422ccb812ee, 0xac62e055c10ab33a, + 0xb616a12b7fe617aa, 0x577b986b314d6009, + 0xe39c49765fdf9d94, 0xed5a7e85fda0b80b, + 0x8e41ade9fbebc27d, 0x14588f13be847307, + 0xb1d219647ae6b31c, 0x596eb2d8ae258fc8, + 0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bb, + 0x8aec23d680043bee, 0x25de7bb9480d5854, + 0xada72ccc20054ae9, 0xaf561aa79a10ae6a, + 0xd910f7ff28069da4, 0x1b2ba1518094da04, + 0x87aa9aff79042286, 0x90fb44d2f05d0842, + 0xa99541bf57452b28, 0x353a1607ac744a53, + 0xd3fa922f2d1675f2, 0x42889b8997915ce8, + 0x847c9b5d7c2e09b7, 0x69956135febada11, + 0xa59bc234db398c25, 0x43fab9837e699095, + 0xcf02b2c21207ef2e, 0x94f967e45e03f4bb, + 0x8161afb94b44f57d, 0x1d1be0eebac278f5, + 0xa1ba1ba79e1632dc, 0x6462d92a69731732, + 0xca28a291859bbf93, 0x7d7b8f7503cfdcfe, + 0xfcb2cb35e702af78, 0x5cda735244c3d43e, + 0x9defbf01b061adab, 0x3a0888136afa64a7, + 0xc56baec21c7a1916, 0x88aaa1845b8fdd0, + 0xf6c69a72a3989f5b, 0x8aad549e57273d45, + 0x9a3c2087a63f6399, 0x36ac54e2f678864b, + 0xc0cb28a98fcf3c7f, 0x84576a1bb416a7dd, + 0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d5, + 0x969eb7c47859e743, 0x9f644ae5a4b1b325, + 0xbc4665b596706114, 0x873d5d9f0dde1fee, + 0xeb57ff22fc0c7959, 0xa90cb506d155a7ea, + 0x9316ff75dd87cbd8, 0x9a7f12442d588f2, + 0xb7dcbf5354e9bece, 0xc11ed6d538aeb2f, + 0xe5d3ef282a242e81, 0x8f1668c8a86da5fa, + 0x8fa475791a569d10, 0xf96e017d694487bc, + 0xb38d92d760ec4455, 0x37c981dcc395a9ac, + 0xe070f78d3927556a, 0x85bbe253f47b1417, + 0x8c469ab843b89562, 0x93956d7478ccec8e, + 0xaf58416654a6babb, 0x387ac8d1970027b2, + 0xdb2e51bfe9d0696a, 0x6997b05fcc0319e, + 0x88fcf317f22241e2, 0x441fece3bdf81f03, + 0xab3c2fddeeaad25a, 0xd527e81cad7626c3, + 0xd60b3bd56a5586f1, 0x8a71e223d8d3b074, + 0x85c7056562757456, 0xf6872d5667844e49, + 0xa738c6bebb12d16c, 0xb428f8ac016561db, + 0xd106f86e69d785c7, 0xe13336d701beba52, + 0x82a45b450226b39c, 0xecc0024661173473, + 0xa34d721642b06084, 0x27f002d7f95d0190, + 0xcc20ce9bd35c78a5, 0x31ec038df7b441f4, + 0xff290242c83396ce, 0x7e67047175a15271, + 0x9f79a169bd203e41, 0xf0062c6e984d386, + 0xc75809c42c684dd1, 0x52c07b78a3e60868, + 0xf92e0c3537826145, 0xa7709a56ccdf8a82, + 0x9bbcc7a142b17ccb, 0x88a66076400bb691, + 0xc2abf989935ddbfe, 0x6acff893d00ea435, + 0xf356f7ebf83552fe, 0x583f6b8c4124d43, + 0x98165af37b2153de, 0xc3727a337a8b704a, + 0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5c, + 0xeda2ee1c7064130c, 0x1162def06f79df73, + 0x9485d4d1c63e8be7, 0x8addcb5645ac2ba8, + 0xb9a74a0637ce2ee1, 0x6d953e2bd7173692, + 0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0437, + 0x910ab1d4db9914a0, 0x1d9c9892400a22a2, + 0xb54d5e4a127f59c8, 0x2503beb6d00cab4b, + 0xe2a0b5dc971f303a, 0x2e44ae64840fd61d, + 0x8da471a9de737e24, 0x5ceaecfed289e5d2, + 0xb10d8e1456105dad, 0x7425a83e872c5f47, + 0xdd50f1996b947518, 0xd12f124e28f77719, + 0x8a5296ffe33cc92f, 0x82bd6b70d99aaa6f, + 0xace73cbfdc0bfb7b, 0x636cc64d1001550b, + 0xd8210befd30efa5a, 0x3c47f7e05401aa4e, + 0x8714a775e3e95c78, 0x65acfaec34810a71, + 0xa8d9d1535ce3b396, 0x7f1839a741a14d0d, + 0xd31045a8341ca07c, 0x1ede48111209a050, + 0x83ea2b892091e44d, 0x934aed0aab460432, + 0xa4e4b66b68b65d60, 0xf81da84d5617853f, + 0xce1de40642e3f4b9, 0x36251260ab9d668e, + 0x80d2ae83e9ce78f3, 0xc1d72b7c6b426019, + 0xa1075a24e4421730, 0xb24cf65b8612f81f, + 0xc94930ae1d529cfc, 0xdee033f26797b627, + 0xfb9b7cd9a4a7443c, 0x169840ef017da3b1, + 0x9d412e0806e88aa5, 0x8e1f289560ee864e, + 0xc491798a08a2ad4e, 0xf1a6f2bab92a27e2, + 0xf5b5d7ec8acb58a2, 0xae10af696774b1db, + 0x9991a6f3d6bf1765, 0xacca6da1e0a8ef29, + 0xbff610b0cc6edd3f, 0x17fd090a58d32af3, + 0xeff394dcff8a948e, 0xddfc4b4cef07f5b0, + 0x95f83d0a1fb69cd9, 0x4abdaf101564f98e, + 0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f1, + 0xea53df5fd18d5513, 0x84c86189216dc5ed, + 0x92746b9be2f8552c, 0x32fd3cf5b4e49bb4, + 0xb7118682dbb66a77, 0x3fbc8c33221dc2a1, + 0xe4d5e82392a40515, 0xfabaf3feaa5334a, + 0x8f05b1163ba6832d, 0x29cb4d87f2a7400e, + 0xb2c71d5bca9023f8, 0x743e20e9ef511012, + 0xdf78e4b2bd342cf6, 0x914da9246b255416, + 0x8bab8eefb6409c1a, 0x1ad089b6c2f7548e, + 0xae9672aba3d0c320, 0xa184ac2473b529b1, + 0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741e, + 0x8865899617fb1871, 0x7e2fa67c7a658892, + 0xaa7eebfb9df9de8d, 0xddbb901b98feeab7, + 0xd51ea6fa85785631, 0x552a74227f3ea565, + 0x8533285c936b35de, 0xd53a88958f87275f, + 0xa67ff273b8460356, 0x8a892abaf368f137, + 0xd01fef10a657842c, 0x2d2b7569b0432d85, + 0x8213f56a67f6b29b, 0x9c3b29620e29fc73, + 0xa298f2c501f45f42, 0x8349f3ba91b47b8f, + 0xcb3f2f7642717713, 0x241c70a936219a73, + 0xfe0efb53d30dd4d7, 0xed238cd383aa0110, + 0x9ec95d1463e8a506, 0xf4363804324a40aa, + 0xc67bb4597ce2ce48, 0xb143c6053edcd0d5, + 0xf81aa16fdc1b81da, 0xdd94b7868e94050a, + 0x9b10a4e5e9913128, 0xca7cf2b4191c8326, + 0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f0, + 0xf24a01a73cf2dccf, 0xbc633b39673c8cec, + 0x976e41088617ca01, 0xd5be0503e085d813, + 0xbd49d14aa79dbc82, 0x4b2d8644d8a74e18, + 0xec9c459d51852ba2, 0xddf8e7d60ed1219e, + 0x93e1ab8252f33b45, 0xcabb90e5c942b503, + 0xb8da1662e7b00a17, 0x3d6a751f3b936243, + 0xe7109bfba19c0c9d, 0xcc512670a783ad4, + 0x906a617d450187e2, 0x27fb2b80668b24c5, + 0xb484f9dc9641e9da, 0xb1f9f660802dedf6, + 0xe1a63853bbd26451, 0x5e7873f8a0396973, + 0x8d07e33455637eb2, 0xdb0b487b6423e1e8, + 0xb049dc016abc5e5f, 0x91ce1a9a3d2cda62, + 0xdc5c5301c56b75f7, 0x7641a140cc7810fb, + 0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9d, + 0xac2820d9623bf429, 0x546345fa9fbdcd44, + 0xd732290fbacaf133, 0xa97c177947ad4095, + 0x867f59a9d4bed6c0, 0x49ed8eabcccc485d, + 0xa81f301449ee8c70, 0x5c68f256bfff5a74, + 0xd226fc195c6a2f8c, 0x73832eec6fff3111, + 0x83585d8fd9c25db7, 0xc831fd53c5ff7eab, + 0xa42e74f3d032f525, 0xba3e7ca8b77f5e55, + 0xcd3a1230c43fb26f, 0x28ce1bd2e55f35eb, + 0x80444b5e7aa7cf85, 0x7980d163cf5b81b3, + 0xa0555e361951c366, 0xd7e105bcc332621f, + 0xc86ab5c39fa63440, 0x8dd9472bf3fefaa7, + 0xfa856334878fc150, 0xb14f98f6f0feb951, + 0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d3, + 0xc3b8358109e84f07, 0xa862f80ec4700c8, + 0xf4a642e14c6262c8, 0xcd27bb612758c0fa, + 0x98e7e9cccfbd7dbd, 0x8038d51cb897789c, + 0xbf21e44003acdd2c, 0xe0470a63e6bd56c3, + 0xeeea5d5004981478, 0x1858ccfce06cac74, + 0x95527a5202df0ccb, 0xf37801e0c43ebc8, + 0xbaa718e68396cffd, 0xd30560258f54e6ba, + 0xe950df20247c83fd, 0x47c6b82ef32a2069, + 0x91d28b7416cdd27e, 0x4cdc331d57fa5441, + 0xb6472e511c81471d, 0xe0133fe4adf8e952, + 0xe3d8f9e563a198e5, 0x58180fddd97723a6, + 0x8e679c2f5e44ff8f, 0x570f09eaa7ea7648 + }; + + private static void AccumulateDecimalDigitsIntoBigInteger(scoped ref NumberBuffer number, uint firstIndex, uint lastIndex, out BigInteger result) + { + BigInteger.SetZero(out result); + + byte* src = number.GetDigitsPointer() + firstIndex; + uint remaining = lastIndex - firstIndex; + + while (remaining != 0) + { + uint count = Math.Min(remaining, 9); + uint value = DigitsToUInt32(src, (int)(count)); + + result.MultiplyPow10(count); + result.Add(value); + + src += count; + remaining -= count; + } + } + + private static ulong AssembleFloatingPointBits(in FloatingPointInfo info, ulong initialMantissa, int initialExponent, bool hasZeroTail) + { + // number of bits by which we must adjust the mantissa to shift it into the + // correct position, and compute the resulting base two exponent for the + // normalized mantissa: + uint initialMantissaBits = BigInteger.CountSignificantBits(initialMantissa); + int normalMantissaShift = info.NormalMantissaBits - (int)(initialMantissaBits); + int normalExponent = initialExponent - normalMantissaShift; + + ulong mantissa = initialMantissa; + int exponent = normalExponent; + + if (normalExponent > info.MaxBinaryExponent) + { + // The exponent is too large to be represented by the floating point + // type; report the overflow condition: + return info.InfinityBits; + } + else if (normalExponent < info.MinBinaryExponent) + { + // The exponent is too small to be represented by the floating point + // type as a normal value, but it may be representable as a denormal + // value. Compute the number of bits by which we need to shift the + // mantissa in order to form a denormal number. (The subtraction of + // an extra 1 is to account for the hidden bit of the mantissa that + // is not available for use when representing a denormal.) + int denormalMantissaShift = normalMantissaShift + normalExponent + info.ExponentBias - 1; + + // Denormal values have an exponent of zero, so the debiased exponent is + // the negation of the exponent bias: + exponent = -info.ExponentBias; + + if (denormalMantissaShift < 0) + { + // Use two steps for right shifts: for a shift of N bits, we first + // shift by N-1 bits, then shift the last bit and use its value to + // round the mantissa. + mantissa = RightShiftWithRounding(mantissa, -denormalMantissaShift, hasZeroTail); + + // If the mantissa is now zero, we have underflowed: + if (mantissa == 0) + { + return info.ZeroBits; + } + + // When we round the mantissa, the result may be so large that the + // number becomes a normal value. For example, consider the single + // precision case where the mantissa is 0x01ffffff and a right shift + // of 2 is required to shift the value into position. We perform the + // shift in two steps: we shift by one bit, then we shift again and + // round using the dropped bit. The initial shift yields 0x00ffffff. + // The rounding shift then yields 0x007fffff and because the least + // significant bit was 1, we add 1 to this number to round it. The + // final result is 0x00800000. + // + // 0x00800000 is 24 bits, which is more than the 23 bits available + // in the mantissa. Thus, we have rounded our denormal number into + // a normal number. + // + // We detect this case here and re-adjust the mantissa and exponent + // appropriately, to form a normal number: + if (mantissa > info.DenormalMantissaMask) + { + // We add one to the denormalMantissaShift to account for the + // hidden mantissa bit (we subtracted one to account for this bit + // when we computed the denormalMantissaShift above). + exponent = initialExponent - (denormalMantissaShift + 1) - normalMantissaShift; + } + } + else + { + mantissa <<= denormalMantissaShift; + } + } + else + { + if (normalMantissaShift < 0) + { + // Use two steps for right shifts: for a shift of N bits, we first + // shift by N-1 bits, then shift the last bit and use its value to + // round the mantissa. + mantissa = RightShiftWithRounding(mantissa, -normalMantissaShift, hasZeroTail); + + // When we round the mantissa, it may produce a result that is too + // large. In this case, we divide the mantissa by two and increment + // the exponent (this does not change the value). + if (mantissa > info.NormalMantissaMask) + { + mantissa >>= 1; + exponent++; + + // The increment of the exponent may have generated a value too + // large to be represented. In this case, report the overflow: + if (exponent > info.MaxBinaryExponent) + { + return info.InfinityBits; + } + } + } + else if (normalMantissaShift > 0) + { + mantissa <<= normalMantissaShift; + } + } + + // Unset the hidden bit in the mantissa and assemble the floating point value + // from the computed components: + mantissa &= info.DenormalMantissaMask; + + Debug.Assert((info.DenormalMantissaMask & (1UL << info.DenormalMantissaBits)) == 0); + ulong shiftedExponent = ((ulong)(exponent + info.ExponentBias)) << info.DenormalMantissaBits; + Debug.Assert((shiftedExponent & info.DenormalMantissaMask) == 0); + Debug.Assert((mantissa & ~info.DenormalMantissaMask) == 0); + Debug.Assert((shiftedExponent & ~(((1UL << info.ExponentBits) - 1) << info.DenormalMantissaBits)) == 0); // exponent fits in its place + + return shiftedExponent | mantissa; + } + + private static ulong ConvertBigIntegerToFloatingPointBits(ref BigInteger value, in FloatingPointInfo info, uint integerBitsOfPrecision, bool hasNonZeroFractionalPart) + { + int baseExponent = info.DenormalMantissaBits; + + // When we have 64-bits or less of precision, we can just get the mantissa directly + if (integerBitsOfPrecision <= 64) + { + return AssembleFloatingPointBits(in info, value.ToUInt64(), baseExponent, !hasNonZeroFractionalPart); + } + + (uint topBlockIndex, uint topBlockBits) = Math.DivRem(integerBitsOfPrecision, 32); + uint middleBlockIndex = topBlockIndex - 1; + uint bottomBlockIndex = middleBlockIndex - 1; + + ulong mantissa; + int exponent = baseExponent + ((int)(bottomBlockIndex) * 32); + bool hasZeroTail = !hasNonZeroFractionalPart; + + // When the top 64-bits perfectly span two blocks, we can get those blocks directly + if (topBlockBits == 0) + { + mantissa = ((ulong)(value.GetBlock(middleBlockIndex)) << 32) + value.GetBlock(bottomBlockIndex); + } + else + { + // Otherwise, we need to read three blocks and combine them into a 64-bit mantissa + + int bottomBlockShift = (int)(topBlockBits); + int topBlockShift = 64 - bottomBlockShift; + int middleBlockShift = topBlockShift - 32; + + exponent += (int)(topBlockBits); + + uint bottomBlock = value.GetBlock(bottomBlockIndex); + uint bottomBits = bottomBlock >> bottomBlockShift; + + ulong middleBits = (ulong)(value.GetBlock(middleBlockIndex)) << middleBlockShift; + ulong topBits = (ulong)(value.GetBlock(topBlockIndex)) << topBlockShift; + + mantissa = topBits + middleBits + bottomBits; + + uint unusedBottomBlockBitsMask = (1u << (int)(topBlockBits)) - 1; + hasZeroTail &= (bottomBlock & unusedBottomBlockBitsMask) == 0; + } + + for (uint i = 0; i != bottomBlockIndex; i++) + { + hasZeroTail &= (value.GetBlock(i) == 0); + } + + return AssembleFloatingPointBits(in info, mantissa, exponent, hasZeroTail); + } + + // get 32-bit integer from at most 9 digits + private static uint DigitsToUInt32(byte* p, int count) + { + Debug.Assert((1 <= count) && (count <= 9)); + + byte* end = (p + count); + uint res = 0; + + // parse batches of 8 digits with SWAR + while (p <= end - 8) + { + res = (res * 100000000) + ParseEightDigitsUnrolled(p); + p += 8; + } + + while (p != end) + { + res = (10 * res) + p[0] - '0'; + ++p; + } + + return res; + } + + // get 64-bit integer from at most 19 digits + private static ulong DigitsToUInt64(byte* p, int count) + { + Debug.Assert((1 <= count) && (count <= 19)); + + byte* end = (p + count); + ulong res = 0; + + // parse batches of 8 digits with SWAR + while (end - p >= 8) + { + res = (res * 100000000) + ParseEightDigitsUnrolled(p); + p += 8; + } + + while (p != end) + { + res = (10 * res) + p[0] - '0'; + ++p; + } + + return res; + } + + /// + /// Parse eight consecutive digits using SWAR + /// https://lemire.me/blog/2022/01/21/swar-explained-parsing-eight-digits/ + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static uint ParseEightDigitsUnrolled(byte* chars) + { + // let's take the following value (byte*) 12345678 and read it unaligned : + // we get a ulong value of 0x3837363534333231 + // 1. Subtract character '0' 0x30 for each byte to get 0x0807060504030201 + // 2. Consider this sequence as bytes sequence : b8b7b6b5b4b3b2b1 + // we need to transform it to b1b2b3b4b5b6b7b8 by computing : + // 10000 * (100 * (10*b1+b2) + 10*b3+b4) + 100*(10*b5+b6) + 10*b7+b8 + // this is achieved by masking and shifting values + ulong val = Unsafe.ReadUnaligned(chars); + + // With BigEndian system an endianness swap has to be performed + // before the following operations as if it has been read with LittleEndian system + if (!BitConverter.IsLittleEndian) + { + val = BinaryPrimitives.ReverseEndianness(val); + } + + const ulong mask = 0x000000FF000000FF; + const ulong mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32) + const ulong mul2 = 0x0000271000000001; // 1 + (10000ULL << 32) + val -= 0x3030303030303030; + val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8; + val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32; + return (uint)val; + } + + private static ulong NumberToDoubleFloatingPointBits(ref NumberBuffer number, in FloatingPointInfo info) + { + Debug.Assert(info.DenormalMantissaBits == 52); + + Debug.Assert(number.GetDigitsPointer()[0] != '0'); + + Debug.Assert(number.Scale <= FloatingPointMaxExponent); + Debug.Assert(number.Scale >= FloatingPointMinExponent); + + Debug.Assert(number.DigitsCount != 0); + + // The input is of the form 0.Mantissa x 10^Exponent, where 'Mantissa' are + // the decimal digits of the mantissa and 'Exponent' is the decimal exponent. + // We decompose the mantissa into two parts: an integer part and a fractional + // part. If the exponent is positive, then the integer part consists of the + // first 'exponent' digits, or all present digits if there are fewer digits. + // If the exponent is zero or negative, then the integer part is empty. In + // either case, the remaining digits form the fractional part of the mantissa. + + uint totalDigits = (uint)(number.DigitsCount); + uint positiveExponent = (uint)(Math.Max(0, number.Scale)); + + uint integerDigitsPresent = Math.Min(positiveExponent, totalDigits); + uint fractionalDigitsPresent = totalDigits - integerDigitsPresent; + + // Above 19 digits, we rely on slow path + if (totalDigits <= 19) + { + byte* src = number.GetDigitsPointer(); + + ulong mantissa = DigitsToUInt64(src, (int)(totalDigits)); + + int exponent = (int)(number.Scale - integerDigitsPresent - fractionalDigitsPresent); + int fastExponent = Math.Abs(exponent); + + // When the number of significant digits is less than or equal to MaxMantissaFastPath and the + // scale is less than or equal to MaxExponentFastPath, we can take some shortcuts and just rely + // on floating-point arithmetic to compute the correct result. This is + // because each floating-point precision values allows us to exactly represent + // different whole integers and certain powers of 10, depending on the underlying + // formats exact range. Additionally, IEEE operations dictate that the result is + // computed to the infinitely precise result and then rounded, which means that + // we can rely on it to produce the correct result when both inputs are exact. + // This is known as Clinger's fast path + + if ((mantissa <= info.MaxMantissaFastPath) && (fastExponent <= info.MaxExponentFastPath)) + { + double mantissa_d = mantissa; + double scale = s_Pow10DoubleTable[fastExponent]; + + if (fractionalDigitsPresent != 0) + { + mantissa_d /= scale; + } + else + { + mantissa_d *= scale; + } + + return BitConverter.DoubleToUInt64Bits(mantissa_d); + } + + // Number Parsing at a Gigabyte per Second, Software: Practice and Experience 51(8), 2021 + // https://arxiv.org/abs/2101.11408 + (int Exponent, ulong Mantissa) am = ComputeFloat(exponent, mantissa, info); + + // If we called ComputeFloat and we have an invalid power of 2 (Exponent < 0), + // then we need to go the slow way around again. This is very uncommon. + if (am.Exponent > 0) + { + ulong word = am.Mantissa; + word |= (ulong)(uint)(am.Exponent) << info.DenormalMantissaBits; + return word; + + } + } + + return NumberToFloatingPointBitsSlow(ref number, in info, positiveExponent, integerDigitsPresent, fractionalDigitsPresent); + } + + private static ushort NumberToHalfFloatingPointBits(ref NumberBuffer number, in FloatingPointInfo info) + { + Debug.Assert(info.DenormalMantissaBits == 10); + + Debug.Assert(number.GetDigitsPointer()[0] != '0'); + + Debug.Assert(number.Scale <= FloatingPointMaxExponent); + Debug.Assert(number.Scale >= FloatingPointMinExponent); + + Debug.Assert(number.DigitsCount != 0); + + // The input is of the form 0.Mantissa x 10^Exponent, where 'Mantissa' are + // the decimal digits of the mantissa and 'Exponent' is the decimal exponent. + // We decompose the mantissa into two parts: an integer part and a fractional + // part. If the exponent is positive, then the integer part consists of the + // first 'exponent' digits, or all present digits if there are fewer digits. + // If the exponent is zero or negative, then the integer part is empty. In + // either case, the remaining digits form the fractional part of the mantissa. + + uint totalDigits = (uint)(number.DigitsCount); + uint positiveExponent = (uint)(Math.Max(0, number.Scale)); + + uint integerDigitsPresent = Math.Min(positiveExponent, totalDigits); + uint fractionalDigitsPresent = totalDigits - integerDigitsPresent; + + int exponent = (int)(number.Scale - integerDigitsPresent - fractionalDigitsPresent); + int fastExponent = Math.Abs(exponent); + + // Above 19 digits, we rely on slow path + if (totalDigits <= 19) + { + byte* src = number.GetDigitsPointer(); + + // When the number of significant digits is less than or equal to MaxMantissaFastPath and the + // scale is less than or equal to MaxExponentFastPath, we can take some shortcuts and just rely + // on floating-point arithmetic to compute the correct result. This is + // because each floating-point precision values allows us to exactly represent + // different whole integers and certain powers of 10, depending on the underlying + // formats exact range. Additionally, IEEE operations dictate that the result is + // computed to the infinitely precise result and then rounded, which means that + // we can rely on it to produce the correct result when both inputs are exact. + // This is known as Clinger's fast path + + ulong mantissa = DigitsToUInt64(src, (int)(totalDigits)); + + if ((mantissa <= info.MaxMantissaFastPath) && (fastExponent <= info.MaxExponentFastPath)) + { + double mantissa_d = mantissa; + double scale = s_Pow10DoubleTable[fastExponent]; + + if (fractionalDigitsPresent != 0) + { + mantissa_d /= scale; + } + else + { + mantissa_d *= scale; + } + + return BitConverter.HalfToUInt16Bits((Half)(mantissa_d)); + } + + // Number Parsing at a Gigabyte per Second, Software: Practice and Experience 51(8), 2021 + // https://arxiv.org/abs/2101.11408 + (int Exponent, ulong Mantissa) am = ComputeFloat(exponent, mantissa, info); + + // If we called ComputeFloat and we have an invalid power of 2 (Exponent < 0), + // then we need to go the slow way around again. This is very uncommon. + if (am.Exponent > 0) + { + ulong word = am.Mantissa; + word |= (ulong)(uint)(am.Exponent) << info.DenormalMantissaBits; + return (ushort)word; + } + + } + return (ushort)NumberToFloatingPointBitsSlow(ref number, in info, positiveExponent, integerDigitsPresent, fractionalDigitsPresent); + } + + private static uint NumberToSingleFloatingPointBits(ref NumberBuffer number, in FloatingPointInfo info) + { + Debug.Assert(info.DenormalMantissaBits == 23); + + Debug.Assert(number.GetDigitsPointer()[0] != '0'); + + Debug.Assert(number.Scale <= FloatingPointMaxExponent); + Debug.Assert(number.Scale >= FloatingPointMinExponent); + + Debug.Assert(number.DigitsCount != 0); + + // The input is of the form 0.Mantissa x 10^Exponent, where 'Mantissa' are + // the decimal digits of the mantissa and 'Exponent' is the decimal exponent. + // We decompose the mantissa into two parts: an integer part and a fractional + // part. If the exponent is positive, then the integer part consists of the + // first 'exponent' digits, or all present digits if there are fewer digits. + // If the exponent is zero or negative, then the integer part is empty. In + // either case, the remaining digits form the fractional part of the mantissa. + + uint totalDigits = (uint)(number.DigitsCount); + uint positiveExponent = (uint)(Math.Max(0, number.Scale)); + + uint integerDigitsPresent = Math.Min(positiveExponent, totalDigits); + uint fractionalDigitsPresent = totalDigits - integerDigitsPresent; + + int exponent = (int)(number.Scale - integerDigitsPresent - fractionalDigitsPresent); + int fastExponent = Math.Abs(exponent); + + + // Above 19 digits, we rely on slow path + if (totalDigits <= 19) + { + + byte* src = number.GetDigitsPointer(); + + // When the number of significant digits is less than or equal to MaxMantissaFastPath and the + // scale is less than or equal to MaxExponentFastPath, we can take some shortcuts and just rely + // on floating-point arithmetic to compute the correct result. This is + // because each floating-point precision values allows us to exactly represent + // different whole integers and certain powers of 10, depending on the underlying + // formats exact range. Additionally, IEEE operations dictate that the result is + // computed to the infinitely precise result and then rounded, which means that + // we can rely on it to produce the correct result when both inputs are exact. + // This is known as Clinger's fast path + + ulong mantissa = DigitsToUInt64(src, (int)(totalDigits)); + + if ((mantissa <= info.MaxMantissaFastPath) && (fastExponent <= info.MaxExponentFastPath)) + { + double mantissa_d = mantissa; + double scale = s_Pow10DoubleTable[fastExponent]; + + if (fractionalDigitsPresent != 0) + { + mantissa_d /= scale; + } + else + { + mantissa_d *= scale; + } + + return BitConverter.SingleToUInt32Bits((float)(mantissa_d)); + } + + // Number Parsing at a Gigabyte per Second, Software: Practice and Experience 51(8), 2021 + // https://arxiv.org/abs/2101.11408 + (int Exponent, ulong Mantissa) am = ComputeFloat(exponent, mantissa, info); + + // If we called ComputeFloat and we have an invalid power of 2 (Exponent < 0), + // then we need to go the slow way around again. This is very uncommon. + if (am.Exponent > 0) + { + ulong word = am.Mantissa; + word |= (ulong)(uint)(am.Exponent) << info.DenormalMantissaBits; + return (uint)word; + } + } + return (uint)NumberToFloatingPointBitsSlow(ref number, in info, positiveExponent, integerDigitsPresent, fractionalDigitsPresent); + } + + private static ulong NumberToFloatingPointBitsSlow(ref NumberBuffer number, in FloatingPointInfo info, uint positiveExponent, uint integerDigitsPresent, uint fractionalDigitsPresent) + { + // To generate an N bit mantissa we require N + 1 bits of precision. The + // extra bit is used to correctly round the mantissa (if there are fewer bits + // than this available, then that's totally okay; in that case we use what we + // have and we don't need to round). + uint requiredBitsOfPrecision = (uint)(info.NormalMantissaBits + 1); + + uint totalDigits = (uint)(number.DigitsCount); + uint integerDigitsMissing = positiveExponent - integerDigitsPresent; + + const uint IntegerFirstIndex = 0; + uint integerLastIndex = integerDigitsPresent; + + uint fractionalFirstIndex = integerLastIndex; + uint fractionalLastIndex = totalDigits; + + // First, we accumulate the integer part of the mantissa into a BigInteger: + AccumulateDecimalDigitsIntoBigInteger(ref number, IntegerFirstIndex, integerLastIndex, out BigInteger integerValue); + + if (integerDigitsMissing > 0) + { + if (integerDigitsMissing > info.OverflowDecimalExponent) + { + return info.InfinityBits; + } + + integerValue.MultiplyPow10(integerDigitsMissing); + } + + // At this point, the integerValue contains the value of the integer part + // of the mantissa. If either [1] this number has more than the required + // number of bits of precision or [2] the mantissa has no fractional part, + // then we can assemble the result immediately: + uint integerBitsOfPrecision = BigInteger.CountSignificantBits(ref integerValue); + + if ((integerBitsOfPrecision >= requiredBitsOfPrecision) || (fractionalDigitsPresent == 0)) + { + return ConvertBigIntegerToFloatingPointBits( + ref integerValue, + in info, + integerBitsOfPrecision, + fractionalDigitsPresent != 0 + ); + } + + // Otherwise, we did not get enough bits of precision from the integer part, + // and the mantissa has a fractional part. We parse the fractional part of + // the mantissa to obtain more bits of precision. To do this, we convert + // the fractional part into an actual fraction N/M, where the numerator N is + // computed from the digits of the fractional part, and the denominator M is + // computed as the power of 10 such that N/M is equal to the value of the + // fractional part of the mantissa. + + uint fractionalDenominatorExponent = fractionalDigitsPresent; + + if (number.Scale < 0) + { + fractionalDenominatorExponent += (uint)(-number.Scale); + } + + if ((integerBitsOfPrecision == 0) && (fractionalDenominatorExponent - (int)(totalDigits)) > info.OverflowDecimalExponent) + { + // If there were any digits in the integer part, it is impossible to + // underflow (because the exponent cannot possibly be small enough), + // so if we underflow here it is a true underflow and we return zero. + return info.ZeroBits; + } + + AccumulateDecimalDigitsIntoBigInteger(ref number, fractionalFirstIndex, fractionalLastIndex, out BigInteger fractionalNumerator); + + if (fractionalNumerator.IsZero()) + { + return ConvertBigIntegerToFloatingPointBits( + ref integerValue, + in info, + integerBitsOfPrecision, + fractionalDigitsPresent != 0 + ); + } + + BigInteger.Pow10(fractionalDenominatorExponent, out BigInteger fractionalDenominator); + + // Because we are using only the fractional part of the mantissa here, the + // numerator is guaranteed to be smaller than the denominator. We normalize + // the fraction such that the most significant bit of the numerator is in + // the same position as the most significant bit in the denominator. This + // ensures that when we later shift the numerator N bits to the left, we + // will produce N bits of precision. + uint fractionalNumeratorBits = BigInteger.CountSignificantBits(ref fractionalNumerator); + uint fractionalDenominatorBits = BigInteger.CountSignificantBits(ref fractionalDenominator); + + uint fractionalShift = 0; + + if (fractionalDenominatorBits > fractionalNumeratorBits) + { + fractionalShift = fractionalDenominatorBits - fractionalNumeratorBits; + } + + if (fractionalShift > 0) + { + fractionalNumerator.ShiftLeft(fractionalShift); + } + + uint requiredFractionalBitsOfPrecision = requiredBitsOfPrecision - integerBitsOfPrecision; + uint remainingBitsOfPrecisionRequired = requiredFractionalBitsOfPrecision; + + if (integerBitsOfPrecision > 0) + { + // If the fractional part of the mantissa provides no bits of precision + // and cannot affect rounding, we can just take whatever bits we got from + // the integer part of the mantissa. This is the case for numbers like + // 5.0000000000000000000001, where the significant digits of the fractional + // part start so far to the right that they do not affect the floating + // point representation. + // + // If the fractional shift is exactly equal to the number of bits of + // precision that we require, then no fractional bits will be part of the + // result, but the result may affect rounding. This is e.g. the case for + // large, odd integers with a fractional part greater than or equal to .5. + // Thus, we need to do the division to correctly round the result. + if (fractionalShift > remainingBitsOfPrecisionRequired) + { + return ConvertBigIntegerToFloatingPointBits( + ref integerValue, + in info, + integerBitsOfPrecision, + fractionalDigitsPresent != 0 + ); + } + + remainingBitsOfPrecisionRequired -= fractionalShift; + } + + // If there was no integer part of the mantissa, we will need to compute the + // exponent from the fractional part. The fractional exponent is the power + // of two by which we must multiply the fractional part to move it into the + // range [1.0, 2.0). This will either be the same as the shift we computed + // earlier, or one greater than that shift: + uint fractionalExponent = fractionalShift; + + if (BigInteger.Compare(ref fractionalNumerator, ref fractionalDenominator) < 0) + { + fractionalExponent++; + } + + fractionalNumerator.ShiftLeft(remainingBitsOfPrecisionRequired); + + BigInteger.DivRem(ref fractionalNumerator, ref fractionalDenominator, out BigInteger bigFractionalMantissa, out BigInteger fractionalRemainder); + ulong fractionalMantissa = bigFractionalMantissa.ToUInt64(); + bool hasZeroTail = !number.HasNonZeroTail && fractionalRemainder.IsZero(); + + // We may have produced more bits of precision than were required. Check, + // and remove any "extra" bits: + uint fractionalMantissaBits = BigInteger.CountSignificantBits(fractionalMantissa); + + if (fractionalMantissaBits > requiredFractionalBitsOfPrecision) + { + int shift = (int)(fractionalMantissaBits - requiredFractionalBitsOfPrecision); + hasZeroTail = hasZeroTail && (fractionalMantissa & ((1UL << shift) - 1)) == 0; + fractionalMantissa >>= shift; + } + + // Compose the mantissa from the integer and fractional parts: + ulong integerMantissa = integerValue.ToUInt64(); + ulong completeMantissa = (integerMantissa << (int)(requiredFractionalBitsOfPrecision)) + fractionalMantissa; + + // Compute the final exponent: + // * If the mantissa had an integer part, then the exponent is one less than + // the number of bits we obtained from the integer part. (It's one less + // because we are converting to the form 1.11111, with one 1 to the left + // of the decimal point.) + // * If the mantissa had no integer part, then the exponent is the fractional + // exponent that we computed. + // Then, in both cases, we subtract an additional one from the exponent, to + // account for the fact that we've generated an extra bit of precision, for + // use in rounding. + int finalExponent = (integerBitsOfPrecision > 0) ? (int)(integerBitsOfPrecision) - 2 : -(int)(fractionalExponent) - 1; + + return AssembleFloatingPointBits(in info, completeMantissa, finalExponent, hasZeroTail); + } + + private static ulong RightShiftWithRounding(ulong value, int shift, bool hasZeroTail) + { + // If we'd need to shift further than it is possible to shift, the answer + // is always zero: + if (shift >= 64) + { + return 0; + } + + ulong extraBitsMask = (1UL << (shift - 1)) - 1; + ulong roundBitMask = (1UL << (shift - 1)); + ulong lsbBitMask = 1UL << shift; + + bool lsbBit = (value & lsbBitMask) != 0; + bool roundBit = (value & roundBitMask) != 0; + bool hasTailBits = !hasZeroTail || (value & extraBitsMask) != 0; + + return (value >> shift) + (ShouldRoundUp(lsbBit, roundBit, hasTailBits) ? 1UL : 0); + } + + private static bool ShouldRoundUp(bool lsbBit, bool roundBit, bool hasTailBits) + { + // If there are insignificant set bits, we need to round to the + // nearest; there are two cases: + // we round up if either [1] the value is slightly greater than the midpoint + // between two exactly representable values or [2] the value is exactly the + // midpoint between two exactly representable values and the greater of the + // two is even (this is "round-to-even"). + return roundBit && (hasTailBits || lsbBit); + } + + + /// + /// Daniel Lemire's Fast-float algorithm please refer to https://arxiv.org/abs/2101.11408 + /// Ojective is to calculate m and p, adjusted mantissa and power of 2, based on the + /// following equality : (m x 2^p) = (w x 10^q) + /// + /// decimal exponent + /// decimal significant (mantissa) + /// parameters for calculations for the value's type (double, float, half) + /// Tuple : Exponent (power of 2) and adjusted mantissa + internal static (int Exponent, ulong Mantissa) ComputeFloat(long q, ulong w, FloatingPointInfo info) + { + int exponent; + ulong mantissa = 0; + + if ((w == 0) || (q < info.MinFastFloatDecimalExponent)) + { + // result should be zero + return default; + } + if (q > info.MaxFastFloatDecimalExponent) + { + // we want to get infinity: + exponent = info.InfinityExponent; + mantissa = 0; + return (exponent, mantissa); + } + + // We want the most significant bit of i to be 1. Shift if needed. + int lz = BitOperations.LeadingZeroCount(w); + w <<= lz; + + // The required precision is info.DenormalMantissaBits + 3 because + // 1. We need the implicit bit + // 2. We need an extra bit for rounding purposes + // 3. We might lose a bit due to the "upperbit" routine (result too small, requiring a shift) + + var product = ComputeProductApproximation(info.DenormalMantissaBits + 3, q, w); + if (product.low == 0xFFFFFFFFFFFFFFFF) + { + // could guard it further + // In some very rare cases, this could happen, in which case we might need a more accurate + // computation that what we can provide cheaply. This is very, very unlikely. + // + bool insideSafeExponent = (q >= -27) && (q <= 55); // always good because 5**q <2**128 when q>=0, + // and otherwise, for q<0, we have 5**-q<2**64 and the 128-bit reciprocal allows for exact computation. + if (!insideSafeExponent) + { + exponent = -1; // This (a negative value) indicates an error condition. + return (exponent, mantissa); + } + } + // The "ComputeProductApproximation" function can be slightly slower than a branchless approach: + // but in practice, we can win big with the ComputeProductApproximation if its additional branch + // is easily predicted. Which is best is data specific. + int upperBit = (int)(product.high >> 63); + + mantissa = product.high >> (upperBit + 64 - info.DenormalMantissaBits - 3); + + exponent = (int)(CalculatePower((int)(q)) + upperBit - lz - (-info.MaxBinaryExponent)); + if (exponent <= 0) + { + // we have a subnormal? + // Here have that answer.power2 <= 0 so -answer.power2 >= 0 + if (-exponent + 1 >= 64) + { + // if we have more than 64 bits below the minimum exponent, you have a zero for sure. + exponent = 0; + mantissa = 0; + // result should be zero + return (exponent, mantissa); + } + // next line is safe because -answer.power2 + 1 < 64 + mantissa >>= -exponent + 1; + // Thankfully, we can't have both "round-to-even" and subnormals because + // "round-to-even" only occurs for powers close to 0. + mantissa += (mantissa & 1); // round up + mantissa >>= 1; + // There is a weird scenario where we don't have a subnormal but just + // suppose we start with 2.2250738585072013e-308, we end up + // with 0x3fffffffffffff x 2^-1023-53 which is technically subnormal + // whereas 0x40000000000000 x 2^-1023-53 is normal. Now, we need to round + // up 0x3fffffffffffff x 2^-1023-53 and once we do, we are no longer + // subnormal, but we can only know this after rounding. + // So we only declare a subnormal if we are smaller than the threshold. + exponent = (mantissa < (1UL << info.DenormalMantissaBits)) ? 0 : 1; + return (exponent, mantissa); + } + + // usually, we round *up*, but if we fall right in between and and we have an + // even basis, we need to round down + // We are only concerned with the cases where 5**q fits in single 64-bit word. + if ((product.low <= 1) && (q >= info.MinExponentRoundToEven) && (q <= info.MaxExponentRoundToEven) && + ((mantissa & 3) == 1)) + { + // We may fall between two floats! + // To be in-between two floats we need that in doing + // answer.mantissa = product.high >> (upperBit + 64 - info.DenormalMantissaBits - 3); + // ... we dropped out only zeroes. But if this happened, then we can go back!!! + if ((mantissa << (upperBit + 64 - info.DenormalMantissaBits - 3)) == product.high) + { + // flip it so that we do not round up + mantissa &= ~1UL; + } + } + + mantissa += (mantissa & 1); // round up + mantissa >>= 1; + if (mantissa >= (2UL << info.DenormalMantissaBits)) + { + mantissa = (1UL << info.DenormalMantissaBits); + // undo previous addition + exponent++; + } + + mantissa &= ~(1UL << info.DenormalMantissaBits); + if (exponent >= info.InfinityExponent) + { + // infinity + exponent = info.InfinityExponent; + mantissa = 0; + } + return (exponent, mantissa); + } + private static (ulong high, ulong low) ComputeProductApproximation(int bitPrecision, long q, ulong w) + { + // -342 being the SmallestPowerOfFive + int index = 2 * (int)(q - -342); + // For small values of q, e.g., q in [0,27], the answer is always exact because + // Math.BigMul gives the exact answer. + ulong high = Math.BigMul(w, s_Pow5128Table[index], out ulong low); + ulong precisionMask = (bitPrecision < 64) ? (0xFFFFFFFFFFFFFFFFUL >> bitPrecision) : 0xFFFFFFFFFFFFFFFFUL; + if ((high & precisionMask) == precisionMask) + { + // could further guard with (lower + w < lower) + // regarding the second product, we only need secondproduct.high, but our expectation is that the compiler will optimize this extra work away if needed. + ulong high2 = Math.BigMul(w, s_Pow5128Table[index + 1], out ulong _); + low += high2; + if (high2 > low) + { + high++; + } + } + return (high, low); + } + + // For q in (0,350), we have that : + // f = (((152170 + 65536) * q) >> 16); + // is equal to + // floor(p) + q + // where + // p = log(5**q)/log(2) = q* log(5)/log(2) + // + // For negative values of q in (-400,0), we have that + // f = (((152170 + 65536) * q) >> 16); + // is equal to : + // -ceil(p) + q + // where + // p = log(5**-q)/log(2) = -q* log(5)/log(2) + // + internal static int CalculatePower(int q) + => (((152170 + 65536) * q) >> 16) + 63; + } +} From d1d9a7f417cd853cf69daac15a472387a7b3a436 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Tue, 20 Dec 2022 15:51:11 -0600 Subject: [PATCH 13/39] Stopping point for parsing, moving to formatting first --- .../src/System/Numerics/IeeeDecimalNumber.cs | 111 +++++++++++++----- 1 file changed, 82 insertions(+), 29 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs index b145e607957ee0..c9fb41509e1f6a 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs @@ -15,18 +15,23 @@ namespace System.Numerics { - - -/* // Extension of NumberFormatInfo to bring in internal helpers, if needed - internal static class NumberFormatInfoExtension +/* // Extension of ReadOnlySpan to bring in internal helpers, if needed + internal static partial class MemoryExtensions { - public static bool Extension_AllowHyphenDuringParsing(this NumberFormatInfo formatInfo) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool EqualsOrdinalIgnoreCase(this ReadOnlySpan span, ReadOnlySpan value) { - return formatInfo.AllowHyphenDuringParsing; + if (span.Length != value.Length) + return false; + if (value.Length == 0) // span.Length == value.Length == 0 + return true; + return System.Globalization.Ordinal.EqualsIgnoreCase(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(value), span.Length); } + + }*/ - internal static class IeeeDecimalNumber + internal static partial class IeeeDecimalNumber { // IeeeDecimalNumberBuffer @@ -176,15 +181,15 @@ internal static unsafe bool TryParseDecimal32(ReadOnlySpan value, NumberSt // to include `PositiveSign`, we need to check whether `PositiveInfinitySymbol` fits // that case so that we don't start parsing things like `++infini`. - if (valueTrim.EqualsOrdinalIgnoreCase(info.PositiveInfinitySymbol)) + if (valueTrim.Equals(info.PositiveInfinitySymbol, StringComparison.OrdinalIgnoreCase)) { result = Decimal32.PositiveInfinity; } - else if (valueTrim.EqualsOrdinalIgnoreCase(info.NegativeInfinitySymbol)) + else if (valueTrim.Equals(info.NegativeInfinitySymbol, StringComparison.OrdinalIgnoreCase)) { result = Decimal32.NegativeInfinity; } - else if (valueTrim.EqualsOrdinalIgnoreCase(info.NaNSymbol)) + else if (valueTrim.Equals(info.NaNSymbol, StringComparison.OrdinalIgnoreCase)) { result = Decimal32.NaN; } @@ -192,11 +197,11 @@ internal static unsafe bool TryParseDecimal32(ReadOnlySpan value, NumberSt { valueTrim = valueTrim.Slice(info.PositiveSign.Length); - if (!info.PositiveInfinitySymbol.StartsWith(info.PositiveSign, StringComparison.OrdinalIgnoreCase) && valueTrim.EqualsOrdinalIgnoreCase(info.PositiveInfinitySymbol)) + if (!info.PositiveInfinitySymbol.StartsWith(info.PositiveSign, StringComparison.OrdinalIgnoreCase) && valueTrim.Equals(info.PositiveInfinitySymbol, StringComparison.OrdinalIgnoreCase)) { result = Decimal32.PositiveInfinity; } - else if (!info.NaNSymbol.StartsWith(info.PositiveSign, StringComparison.OrdinalIgnoreCase) && valueTrim.EqualsOrdinalIgnoreCase(info.NaNSymbol)) + else if (!info.NaNSymbol.StartsWith(info.PositiveSign, StringComparison.OrdinalIgnoreCase) && valueTrim.Equals(info.NaNSymbol, StringComparison.OrdinalIgnoreCase)) { result = Decimal32.NaN; } @@ -208,12 +213,12 @@ internal static unsafe bool TryParseDecimal32(ReadOnlySpan value, NumberSt } else if (valueTrim.StartsWith(info.NegativeSign, StringComparison.OrdinalIgnoreCase) && !info.NaNSymbol.StartsWith(info.NegativeSign, StringComparison.OrdinalIgnoreCase) && - valueTrim.Slice(info.NegativeSign.Length).EqualsOrdinalIgnoreCase(info.NaNSymbol)) + valueTrim.Slice(info.NegativeSign.Length).Equals(info.NaNSymbol, StringComparison.OrdinalIgnoreCase)) { result = Decimal32.NaN; } else if (info.AllowHyphenDuringParsing && SpanStartsWith(valueTrim, '-') && !info.NaNSymbol.StartsWith(info.NegativeSign, StringComparison.OrdinalIgnoreCase) && - !info.NaNSymbol.StartsWith('-') && valueTrim.Slice(1).EqualsOrdinalIgnoreCase(info.NaNSymbol)) + !info.NaNSymbol.StartsWith('-') && valueTrim.Slice(1).Equals(info.NaNSymbol, StringComparison.OrdinalIgnoreCase)) { result = Decimal32.NaN; } @@ -352,10 +357,10 @@ private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, Nu if (digCount < maxDigCount) { number.Digits[digCount] = (byte)(ch); - if ((ch != '0') || (number.Kind != NumberBufferKind.Integer)) - { + //if ((ch != '0') || (number.Kind != NumberBufferKind.Integer)) // number.Kind will always not be Integer + //{ digEnd = digCount + 1; - } + //} } else if (ch != '0') { @@ -457,7 +462,7 @@ private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, Nu } } - if (number.Kind == NumberBufferKind.FloatingPoint && !number.HasNonZeroTail) + if (/*number.Kind == NumberBufferKind.FloatingPoint && // <- this will always be true */!number.HasNonZeroTail) { // Adjust the number buffer for trailing zeros int numberOfFractionalDigits = digEnd - number.Scale; @@ -499,14 +504,15 @@ private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, Nu { if ((state & StateNonZero) == 0) { - if (number.Kind != NumberBufferKind.Decimal) + // Both of the below should always be false. I believe the first case is handling a specific edge case for System.Decimal that does not apply to the IEEE Decimals. TODO confirm this. +/* if (number.Kind != NumberBufferKind.Decimal) { number.Scale = 0; } if ((number.Kind == NumberBufferKind.Integer) && (state & StateDecimal) == 0) { number.IsNegative = false; - } + }*/ } str = p; return true; @@ -563,26 +569,73 @@ private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, Nu private static bool IsDigit(int ch) => ((uint)ch - '0') <= 9; - internal static Decimal32 NumberToDecimal32(ref IeeeDecimalNumberBuffer number) + internal static unsafe Decimal32 NumberToDecimal32(ref IeeeDecimalNumberBuffer number) { number.CheckConsistency(); - Decimal32 result; + //Decimal32 result; + return default; // TODO figure this out after formatting - if ((number.DigitsCount == 0) || (number.Scale < Decimal32.MinQExponent)) + // The input value is of the form 0.Mantissa x 10^Exponent, where 'Mantissa' are + // the decimal digits of the mantissa and 'Exponent' is the decimal exponent. + // We want to extract q (the exponent) and c (the significand) such that + // value = c * 10 ^ q + // Which means + // c = first N digits of Mantissa, where N is min(Decimal32.Precision, number.DigitsCount) + // - Note: If there are more than Decimal32.Precision digits in the number, we must round + // q = Exponent - N + // - Note: If Exponent - N cannot fit in q we need to adjust c and round + + // Step 1: Adjust the exponent such that the value Mantissa.ExtraDigits x 10^Exponent +/* int q = number.Scale - 7; + + + if ((number.DigitsCount == 0) || ((q < Decimal32.MinQExponent) && number.DigitsCount)) { - result = default; + result = default; // TODO are we sure this is the "right" zero to return in all these cases } - else if (number.Scale > Decimal32.MaxQExponent) + else if (q > Decimal32.MaxQExponent) { result = Decimal32.PositiveInfinity; } else { - ushort bits = NumberToDecimal32FloatingPointBits(ref number, in FloatingPointInfo.Decimal32); - result = new Decimal32(bits); - } - return number.IsNegative ? Decimal32.Negate(result) : result; + + // Step 1: Adjust + + byte* mantissa = number.GetDigitsPointer(); + int exponent = number.Scale; + uint digit = *mantissa; + + + uint digitsToExtract; + bool needToRound; + if (number.DigitsCount > Decimal32.Precision) + { + digitsToExtract = Decimal32.Precision; + needToRound = true; + } + else + { + digitsToExtract = (uint) number.DigitsCount; + needToRound = false; + } + + + uint c = 0; + int q = number.Scale; + uint extractedDigits = 0; + while (true) + { + if ( + c *= 10; + q -= 1; + } + + + } + + return number.IsNegative ? Decimal32.Negate(result) : result;*/ } internal enum ParsingStatus // No ParsingStatus.Overflow because these types can represent infinity From 3967c80cbd93d13b19dfeda3e81243ef6f271a9f Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Wed, 21 Dec 2022 13:18:27 -0600 Subject: [PATCH 14/39] Just kidding, continuing to work on parsing. I think this is complete. --- .../src/System.Runtime.Numerics.csproj | 1 - .../src/System/Numerics/Decimal32.cs | 18 +- ...DecimalNumber.NumberToFloatingPointBits.cs | 1683 ----------------- .../src/System/Numerics/IeeeDecimalNumber.cs | 145 +- 4 files changed, 108 insertions(+), 1739 deletions(-) delete mode 100644 src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.NumberToFloatingPointBits.cs diff --git a/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj b/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj index dd51d48464adbe..be5c8efa5eab43 100644 --- a/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj +++ b/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj @@ -7,7 +7,6 @@ - diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index 91c1a10a7259e4..c26b0c29fa9b29 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; @@ -49,9 +50,8 @@ public readonly struct Decimal32 internal const sbyte MaxQExponent = EMax - Precision + 1; internal const sbyte MinQExponent = EMin - Precision + 1; - // TODO I think these might be useless in Decimal - /* internal const uint MinTrailingSignificand = 0x0000_0000; - internal const uint MaxTrailingSignificand = 0x000F_FFFF; // TODO double check this, might be artificially bounded below this*/ + internal const int MaxSignificand = 9999999; + internal const int MinSignificand = -9999999; // Constants representing the private bit-representation for various default values. // See either IEEE-754 2019 section 3.5 or https://en.wikipedia.org/wiki/Decimal32_floating-point_format for a breakdown of the encoding. @@ -195,9 +195,17 @@ internal Decimal32(uint value) } private Decimal32(bool sign, uint combination, uint trailing_sig) => _value = (uint)(((sign ? 1 : 0) << SignShift) + (combination << CombinationShift) + trailing_sig); // TODO do we need this? - private Decimal32(bool sign, uint q, uint sig) + + // Constructs a Decimal32 representing a value in the form (-1)^s * 10^q * c, where + // * s is 0 or 1 + // * q is any integer MinQExponent <= q <= MaxQExponent + // * c is the significand represented by a digit string of the form + // `d0 d1 d2 ... dp-1`, where p is Precision. c is an integer with 0 <= c < 10^p. + internal Decimal32(bool s, sbyte q, uint c) { - // Edge conditions: MinQExponent <= q <= MaxQExponent, 0 <= sig <= 9999999 + // Edge conditions: MinQExponent <= q <= MaxQExponent, 0 <= s <= 9999999 + Debug.Assert(q >= MinQExponent && q <= MaxQExponent); + Debug.Assert(c <= MaxSignificand); _value = 0; // TODO } diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.NumberToFloatingPointBits.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.NumberToFloatingPointBits.cs deleted file mode 100644 index 221734a983545c..00000000000000 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.NumberToFloatingPointBits.cs +++ /dev/null @@ -1,1683 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers.Binary; -using System.Diagnostics; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace System -{ - internal unsafe partial class IeeeDecimalNumber - { - public readonly struct FloatingPointInfo - { - public static readonly FloatingPointInfo Double = new FloatingPointInfo( - denormalMantissaBits: 52, - exponentBits: 11, - maxBinaryExponent: 1023, - exponentBias: 1023, - infinityBits: 0x7FF00000_00000000, - minFastFloatDecimalExponent: -342, - maxFastFloatDecimalExponent: 308, - infinityExponent: 0x7FF, - minExponentRoundToEven: -4, - maxExponentRoundToEven: 23, - maxExponentFastPath: 22 - ); - - public static readonly FloatingPointInfo Single = new FloatingPointInfo( - denormalMantissaBits: 23, - exponentBits: 8, - maxBinaryExponent: 127, - exponentBias: 127, - infinityBits: 0x7F800000, - minFastFloatDecimalExponent: -65, - maxFastFloatDecimalExponent: 38, - infinityExponent: 0xFF, - minExponentRoundToEven: -17, - maxExponentRoundToEven: 10, - maxExponentFastPath: 10 - ); - public static readonly FloatingPointInfo Half = new FloatingPointInfo( - denormalMantissaBits: 10, - exponentBits: 5, - maxBinaryExponent: 15, - exponentBias: 15, - infinityBits: 0x7C00, - minFastFloatDecimalExponent: -8, - maxFastFloatDecimalExponent: 4, - infinityExponent: 0x1F, - minExponentRoundToEven: -21, - maxExponentRoundToEven: 5, - maxExponentFastPath: 4 - ); - - public ulong ZeroBits { get; } - public ulong InfinityBits { get; } - - public ulong NormalMantissaMask { get; } - public ulong DenormalMantissaMask { get; } - - public int MinBinaryExponent { get; } - public int MaxBinaryExponent { get; } - - public int ExponentBias { get; } - public int OverflowDecimalExponent { get; } - - public ushort NormalMantissaBits { get; } - public ushort DenormalMantissaBits { get; } - - public int MinFastFloatDecimalExponent { get; } - public int InfinityExponent { get; } - public int MinExponentRoundToEven { get; } - public int MaxExponentRoundToEven { get; } - - public int MaxExponentFastPath { get; } - - public int MaxFastFloatDecimalExponent { get; } - public ulong MaxMantissaFastPath { get => 2UL << DenormalMantissaBits; } - public ushort ExponentBits { get; } - - public FloatingPointInfo(ushort denormalMantissaBits, ushort exponentBits, int maxBinaryExponent, int exponentBias, ulong infinityBits, int minFastFloatDecimalExponent, int maxFastFloatDecimalExponent, int infinityExponent, int minExponentRoundToEven, int maxExponentRoundToEven, int maxExponentFastPath) - { - ExponentBits = exponentBits; - - DenormalMantissaBits = denormalMantissaBits; - NormalMantissaBits = (ushort)(denormalMantissaBits + 1); // we get an extra (hidden) bit for normal mantissas - - OverflowDecimalExponent = (maxBinaryExponent + 2 * NormalMantissaBits) / 3; - ExponentBias = exponentBias; - - MaxBinaryExponent = maxBinaryExponent; - MinBinaryExponent = 1 - maxBinaryExponent; - - DenormalMantissaMask = (1UL << denormalMantissaBits) - 1; - NormalMantissaMask = (1UL << NormalMantissaBits) - 1; - - InfinityBits = infinityBits; - ZeroBits = 0; - - MaxFastFloatDecimalExponent = maxFastFloatDecimalExponent; - MinFastFloatDecimalExponent = minFastFloatDecimalExponent; - - InfinityExponent = infinityExponent; - - MinExponentRoundToEven = minExponentRoundToEven; - MaxExponentRoundToEven = maxExponentRoundToEven; - - MaxExponentFastPath = maxExponentFastPath; - } - } - - private static readonly double[] s_Pow10DoubleTable = { - 1e0, // 10^0 - 1e1, // 10^1 - 1e2, // 10^2 - 1e3, // 10^3 - 1e4, // 10^4 - 1e5, // 10^5 - 1e6, // 10^6 - 1e7, // 10^7 - 1e8, // 10^8 - 1e9, // 10^9 - 1e10, // 10^10 - 1e11, // 10^11 - 1e12, // 10^12 - 1e13, // 10^13 - 1e14, // 10^14 - 1e15, // 10^15 - 1e16, // 10^16 - 1e17, // 10^17 - 1e18, // 10^18 - 1e19, // 10^19 - 1e20, // 10^20 - 1e21, // 10^21 - 1e22, // 10^22 - }; - - /// - /// Normalized 128 bits values for powers of 5^q for q in range [-342, 308] - /// stored as 2 64-bits integers for convenience - /// - private static readonly ulong[] s_Pow5128Table = { - 0xeef453d6923bd65a, 0x113faa2906a13b3f, - 0x9558b4661b6565f8, 0x4ac7ca59a424c507, - 0xbaaee17fa23ebf76, 0x5d79bcf00d2df649, - 0xe95a99df8ace6f53, 0xf4d82c2c107973dc, - 0x91d8a02bb6c10594, 0x79071b9b8a4be869, - 0xb64ec836a47146f9, 0x9748e2826cdee284, - 0xe3e27a444d8d98b7, 0xfd1b1b2308169b25, - 0x8e6d8c6ab0787f72, 0xfe30f0f5e50e20f7, - 0xb208ef855c969f4f, 0xbdbd2d335e51a935, - 0xde8b2b66b3bc4723, 0xad2c788035e61382, - 0x8b16fb203055ac76, 0x4c3bcb5021afcc31, - 0xaddcb9e83c6b1793, 0xdf4abe242a1bbf3d, - 0xd953e8624b85dd78, 0xd71d6dad34a2af0d, - 0x87d4713d6f33aa6b, 0x8672648c40e5ad68, - 0xa9c98d8ccb009506, 0x680efdaf511f18c2, - 0xd43bf0effdc0ba48, 0x212bd1b2566def2, - 0x84a57695fe98746d, 0x14bb630f7604b57, - 0xa5ced43b7e3e9188, 0x419ea3bd35385e2d, - 0xcf42894a5dce35ea, 0x52064cac828675b9, - 0x818995ce7aa0e1b2, 0x7343efebd1940993, - 0xa1ebfb4219491a1f, 0x1014ebe6c5f90bf8, - 0xca66fa129f9b60a6, 0xd41a26e077774ef6, - 0xfd00b897478238d0, 0x8920b098955522b4, - 0x9e20735e8cb16382, 0x55b46e5f5d5535b0, - 0xc5a890362fddbc62, 0xeb2189f734aa831d, - 0xf712b443bbd52b7b, 0xa5e9ec7501d523e4, - 0x9a6bb0aa55653b2d, 0x47b233c92125366e, - 0xc1069cd4eabe89f8, 0x999ec0bb696e840a, - 0xf148440a256e2c76, 0xc00670ea43ca250d, - 0x96cd2a865764dbca, 0x380406926a5e5728, - 0xbc807527ed3e12bc, 0xc605083704f5ecf2, - 0xeba09271e88d976b, 0xf7864a44c633682e, - 0x93445b8731587ea3, 0x7ab3ee6afbe0211d, - 0xb8157268fdae9e4c, 0x5960ea05bad82964, - 0xe61acf033d1a45df, 0x6fb92487298e33bd, - 0x8fd0c16206306bab, 0xa5d3b6d479f8e056, - 0xb3c4f1ba87bc8696, 0x8f48a4899877186c, - 0xe0b62e2929aba83c, 0x331acdabfe94de87, - 0x8c71dcd9ba0b4925, 0x9ff0c08b7f1d0b14, - 0xaf8e5410288e1b6f, 0x7ecf0ae5ee44dd9, - 0xdb71e91432b1a24a, 0xc9e82cd9f69d6150, - 0x892731ac9faf056e, 0xbe311c083a225cd2, - 0xab70fe17c79ac6ca, 0x6dbd630a48aaf406, - 0xd64d3d9db981787d, 0x92cbbccdad5b108, - 0x85f0468293f0eb4e, 0x25bbf56008c58ea5, - 0xa76c582338ed2621, 0xaf2af2b80af6f24e, - 0xd1476e2c07286faa, 0x1af5af660db4aee1, - 0x82cca4db847945ca, 0x50d98d9fc890ed4d, - 0xa37fce126597973c, 0xe50ff107bab528a0, - 0xcc5fc196fefd7d0c, 0x1e53ed49a96272c8, - 0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7a, - 0x9faacf3df73609b1, 0x77b191618c54e9ac, - 0xc795830d75038c1d, 0xd59df5b9ef6a2417, - 0xf97ae3d0d2446f25, 0x4b0573286b44ad1d, - 0x9becce62836ac577, 0x4ee367f9430aec32, - 0xc2e801fb244576d5, 0x229c41f793cda73f, - 0xf3a20279ed56d48a, 0x6b43527578c1110f, - 0x9845418c345644d6, 0x830a13896b78aaa9, - 0xbe5691ef416bd60c, 0x23cc986bc656d553, - 0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa8, - 0x94b3a202eb1c3f39, 0x7bf7d71432f3d6a9, - 0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc53, - 0xe858ad248f5c22c9, 0xd1b3400f8f9cff68, - 0x91376c36d99995be, 0x23100809b9c21fa1, - 0xb58547448ffffb2d, 0xabd40a0c2832a78a, - 0xe2e69915b3fff9f9, 0x16c90c8f323f516c, - 0x8dd01fad907ffc3b, 0xae3da7d97f6792e3, - 0xb1442798f49ffb4a, 0x99cd11cfdf41779c, - 0xdd95317f31c7fa1d, 0x40405643d711d583, - 0x8a7d3eef7f1cfc52, 0x482835ea666b2572, - 0xad1c8eab5ee43b66, 0xda3243650005eecf, - 0xd863b256369d4a40, 0x90bed43e40076a82, - 0x873e4f75e2224e68, 0x5a7744a6e804a291, - 0xa90de3535aaae202, 0x711515d0a205cb36, - 0xd3515c2831559a83, 0xd5a5b44ca873e03, - 0x8412d9991ed58091, 0xe858790afe9486c2, - 0xa5178fff668ae0b6, 0x626e974dbe39a872, - 0xce5d73ff402d98e3, 0xfb0a3d212dc8128f, - 0x80fa687f881c7f8e, 0x7ce66634bc9d0b99, - 0xa139029f6a239f72, 0x1c1fffc1ebc44e80, - 0xc987434744ac874e, 0xa327ffb266b56220, - 0xfbe9141915d7a922, 0x4bf1ff9f0062baa8, - 0x9d71ac8fada6c9b5, 0x6f773fc3603db4a9, - 0xc4ce17b399107c22, 0xcb550fb4384d21d3, - 0xf6019da07f549b2b, 0x7e2a53a146606a48, - 0x99c102844f94e0fb, 0x2eda7444cbfc426d, - 0xc0314325637a1939, 0xfa911155fefb5308, - 0xf03d93eebc589f88, 0x793555ab7eba27ca, - 0x96267c7535b763b5, 0x4bc1558b2f3458de, - 0xbbb01b9283253ca2, 0x9eb1aaedfb016f16, - 0xea9c227723ee8bcb, 0x465e15a979c1cadc, - 0x92a1958a7675175f, 0xbfacd89ec191ec9, - 0xb749faed14125d36, 0xcef980ec671f667b, - 0xe51c79a85916f484, 0x82b7e12780e7401a, - 0x8f31cc0937ae58d2, 0xd1b2ecb8b0908810, - 0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa15, - 0xdfbdcece67006ac9, 0x67a791e093e1d49a, - 0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e0, - 0xaecc49914078536d, 0x58fae9f773886e18, - 0xda7f5bf590966848, 0xaf39a475506a899e, - 0x888f99797a5e012d, 0x6d8406c952429603, - 0xaab37fd7d8f58178, 0xc8e5087ba6d33b83, - 0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a64, - 0x855c3be0a17fcd26, 0x5cf2eea09a55067f, - 0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481e, - 0xd0601d8efc57b08b, 0xf13b94daf124da26, - 0x823c12795db6ce57, 0x76c53d08d6b70858, - 0xa2cb1717b52481ed, 0x54768c4b0c64ca6e, - 0xcb7ddcdda26da268, 0xa9942f5dcf7dfd09, - 0xfe5d54150b090b02, 0xd3f93b35435d7c4c, - 0x9efa548d26e5a6e1, 0xc47bc5014a1a6daf, - 0xc6b8e9b0709f109a, 0x359ab6419ca1091b, - 0xf867241c8cc6d4c0, 0xc30163d203c94b62, - 0x9b407691d7fc44f8, 0x79e0de63425dcf1d, - 0xc21094364dfb5636, 0x985915fc12f542e4, - 0xf294b943e17a2bc4, 0x3e6f5b7b17b2939d, - 0x979cf3ca6cec5b5a, 0xa705992ceecf9c42, - 0xbd8430bd08277231, 0x50c6ff782a838353, - 0xece53cec4a314ebd, 0xa4f8bf5635246428, - 0x940f4613ae5ed136, 0x871b7795e136be99, - 0xb913179899f68584, 0x28e2557b59846e3f, - 0xe757dd7ec07426e5, 0x331aeada2fe589cf, - 0x9096ea6f3848984f, 0x3ff0d2c85def7621, - 0xb4bca50b065abe63, 0xfed077a756b53a9, - 0xe1ebce4dc7f16dfb, 0xd3e8495912c62894, - 0x8d3360f09cf6e4bd, 0x64712dd7abbbd95c, - 0xb080392cc4349dec, 0xbd8d794d96aacfb3, - 0xdca04777f541c567, 0xecf0d7a0fc5583a0, - 0x89e42caaf9491b60, 0xf41686c49db57244, - 0xac5d37d5b79b6239, 0x311c2875c522ced5, - 0xd77485cb25823ac7, 0x7d633293366b828b, - 0x86a8d39ef77164bc, 0xae5dff9c02033197, - 0xa8530886b54dbdeb, 0xd9f57f830283fdfc, - 0xd267caa862a12d66, 0xd072df63c324fd7b, - 0x8380dea93da4bc60, 0x4247cb9e59f71e6d, - 0xa46116538d0deb78, 0x52d9be85f074e608, - 0xcd795be870516656, 0x67902e276c921f8b, - 0x806bd9714632dff6, 0xba1cd8a3db53b6, - 0xa086cfcd97bf97f3, 0x80e8a40eccd228a4, - 0xc8a883c0fdaf7df0, 0x6122cd128006b2cd, - 0xfad2a4b13d1b5d6c, 0x796b805720085f81, - 0x9cc3a6eec6311a63, 0xcbe3303674053bb0, - 0xc3f490aa77bd60fc, 0xbedbfc4411068a9c, - 0xf4f1b4d515acb93b, 0xee92fb5515482d44, - 0x991711052d8bf3c5, 0x751bdd152d4d1c4a, - 0xbf5cd54678eef0b6, 0xd262d45a78a0635d, - 0xef340a98172aace4, 0x86fb897116c87c34, - 0x9580869f0e7aac0e, 0xd45d35e6ae3d4da0, - 0xbae0a846d2195712, 0x8974836059cca109, - 0xe998d258869facd7, 0x2bd1a438703fc94b, - 0x91ff83775423cc06, 0x7b6306a34627ddcf, - 0xb67f6455292cbf08, 0x1a3bc84c17b1d542, - 0xe41f3d6a7377eeca, 0x20caba5f1d9e4a93, - 0x8e938662882af53e, 0x547eb47b7282ee9c, - 0xb23867fb2a35b28d, 0xe99e619a4f23aa43, - 0xdec681f9f4c31f31, 0x6405fa00e2ec94d4, - 0x8b3c113c38f9f37e, 0xde83bc408dd3dd04, - 0xae0b158b4738705e, 0x9624ab50b148d445, - 0xd98ddaee19068c76, 0x3badd624dd9b0957, - 0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d6, - 0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4c, - 0xd47487cc8470652b, 0x7647c3200069671f, - 0x84c8d4dfd2c63f3b, 0x29ecd9f40041e073, - 0xa5fb0a17c777cf09, 0xf468107100525890, - 0xcf79cc9db955c2cc, 0x7182148d4066eeb4, - 0x81ac1fe293d599bf, 0xc6f14cd848405530, - 0xa21727db38cb002f, 0xb8ada00e5a506a7c, - 0xca9cf1d206fdc03b, 0xa6d90811f0e4851c, - 0xfd442e4688bd304a, 0x908f4a166d1da663, - 0x9e4a9cec15763e2e, 0x9a598e4e043287fe, - 0xc5dd44271ad3cdba, 0x40eff1e1853f29fd, - 0xf7549530e188c128, 0xd12bee59e68ef47c, - 0x9a94dd3e8cf578b9, 0x82bb74f8301958ce, - 0xc13a148e3032d6e7, 0xe36a52363c1faf01, - 0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac1, - 0x96f5600f15a7b7e5, 0x29ab103a5ef8c0b9, - 0xbcb2b812db11a5de, 0x7415d448f6b6f0e7, - 0xebdf661791d60f56, 0x111b495b3464ad21, - 0x936b9fcebb25c995, 0xcab10dd900beec34, - 0xb84687c269ef3bfb, 0x3d5d514f40eea742, - 0xe65829b3046b0afa, 0xcb4a5a3112a5112, - 0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ab, - 0xb3f4e093db73a093, 0x59ed216765690f56, - 0xe0f218b8d25088b8, 0x306869c13ec3532c, - 0x8c974f7383725573, 0x1e414218c73a13fb, - 0xafbd2350644eeacf, 0xe5d1929ef90898fa, - 0xdbac6c247d62a583, 0xdf45f746b74abf39, - 0x894bc396ce5da772, 0x6b8bba8c328eb783, - 0xab9eb47c81f5114f, 0x66ea92f3f326564, - 0xd686619ba27255a2, 0xc80a537b0efefebd, - 0x8613fd0145877585, 0xbd06742ce95f5f36, - 0xa798fc4196e952e7, 0x2c48113823b73704, - 0xd17f3b51fca3a7a0, 0xf75a15862ca504c5, - 0x82ef85133de648c4, 0x9a984d73dbe722fb, - 0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebba, - 0xcc963fee10b7d1b3, 0x318df905079926a8, - 0xffbbcfe994e5c61f, 0xfdf17746497f7052, - 0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa633, - 0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc0, - 0xf9bd690a1b68637b, 0x3dfdce7aa3c673b0, - 0x9c1661a651213e2d, 0x6bea10ca65c084e, - 0xc31bfa0fe5698db8, 0x486e494fcff30a62, - 0xf3e2f893dec3f126, 0x5a89dba3c3efccfa, - 0x986ddb5c6b3a76b7, 0xf89629465a75e01c, - 0xbe89523386091465, 0xf6bbb397f1135823, - 0xee2ba6c0678b597f, 0x746aa07ded582e2c, - 0x94db483840b717ef, 0xa8c2a44eb4571cdc, - 0xba121a4650e4ddeb, 0x92f34d62616ce413, - 0xe896a0d7e51e1566, 0x77b020baf9c81d17, - 0x915e2486ef32cd60, 0xace1474dc1d122e, - 0xb5b5ada8aaff80b8, 0xd819992132456ba, - 0xe3231912d5bf60e6, 0x10e1fff697ed6c69, - 0x8df5efabc5979c8f, 0xca8d3ffa1ef463c1, - 0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb2, - 0xddd0467c64bce4a0, 0xac7cb3f6d05ddbde, - 0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96b, - 0xad4ab7112eb3929d, 0x86c16c98d2c953c6, - 0xd89d64d57a607744, 0xe871c7bf077ba8b7, - 0x87625f056c7c4a8b, 0x11471cd764ad4972, - 0xa93af6c6c79b5d2d, 0xd598e40d3dd89bcf, - 0xd389b47879823479, 0x4aff1d108d4ec2c3, - 0x843610cb4bf160cb, 0xcedf722a585139ba, - 0xa54394fe1eedb8fe, 0xc2974eb4ee658828, - 0xce947a3da6a9273e, 0x733d226229feea32, - 0x811ccc668829b887, 0x806357d5a3f525f, - 0xa163ff802a3426a8, 0xca07c2dcb0cf26f7, - 0xc9bcff6034c13052, 0xfc89b393dd02f0b5, - 0xfc2c3f3841f17c67, 0xbbac2078d443ace2, - 0x9d9ba7832936edc0, 0xd54b944b84aa4c0d, - 0xc5029163f384a931, 0xa9e795e65d4df11, - 0xf64335bcf065d37d, 0x4d4617b5ff4a16d5, - 0x99ea0196163fa42e, 0x504bced1bf8e4e45, - 0xc06481fb9bcf8d39, 0xe45ec2862f71e1d6, - 0xf07da27a82c37088, 0x5d767327bb4e5a4c, - 0x964e858c91ba2655, 0x3a6a07f8d510f86f, - 0xbbe226efb628afea, 0x890489f70a55368b, - 0xeadab0aba3b2dbe5, 0x2b45ac74ccea842e, - 0x92c8ae6b464fc96f, 0x3b0b8bc90012929d, - 0xb77ada0617e3bbcb, 0x9ce6ebb40173744, - 0xe55990879ddcaabd, 0xcc420a6a101d0515, - 0x8f57fa54c2a9eab6, 0x9fa946824a12232d, - 0xb32df8e9f3546564, 0x47939822dc96abf9, - 0xdff9772470297ebd, 0x59787e2b93bc56f7, - 0x8bfbea76c619ef36, 0x57eb4edb3c55b65a, - 0xaefae51477a06b03, 0xede622920b6b23f1, - 0xdab99e59958885c4, 0xe95fab368e45eced, - 0x88b402f7fd75539b, 0x11dbcb0218ebb414, - 0xaae103b5fcd2a881, 0xd652bdc29f26a119, - 0xd59944a37c0752a2, 0x4be76d3346f0495f, - 0x857fcae62d8493a5, 0x6f70a4400c562ddb, - 0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb952, - 0xd097ad07a71f26b2, 0x7e2000a41346a7a7, - 0x825ecc24c873782f, 0x8ed400668c0c28c8, - 0xa2f67f2dfa90563b, 0x728900802f0f32fa, - 0xcbb41ef979346bca, 0x4f2b40a03ad2ffb9, - 0xfea126b7d78186bc, 0xe2f610c84987bfa8, - 0x9f24b832e6b0f436, 0xdd9ca7d2df4d7c9, - 0xc6ede63fa05d3143, 0x91503d1c79720dbb, - 0xf8a95fcf88747d94, 0x75a44c6397ce912a, - 0x9b69dbe1b548ce7c, 0xc986afbe3ee11aba, - 0xc24452da229b021b, 0xfbe85badce996168, - 0xf2d56790ab41c2a2, 0xfae27299423fb9c3, - 0x97c560ba6b0919a5, 0xdccd879fc967d41a, - 0xbdb6b8e905cb600f, 0x5400e987bbc1c920, - 0xed246723473e3813, 0x290123e9aab23b68, - 0x9436c0760c86e30b, 0xf9a0b6720aaf6521, - 0xb94470938fa89bce, 0xf808e40e8d5b3e69, - 0xe7958cb87392c2c2, 0xb60b1d1230b20e04, - 0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c2, - 0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af3, - 0xe2280b6c20dd5232, 0x25c6da63c38de1b0, - 0x8d590723948a535f, 0x579c487e5a38ad0e, - 0xb0af48ec79ace837, 0x2d835a9df0c6d851, - 0xdcdb1b2798182244, 0xf8e431456cf88e65, - 0x8a08f0f8bf0f156b, 0x1b8e9ecb641b58ff, - 0xac8b2d36eed2dac5, 0xe272467e3d222f3f, - 0xd7adf884aa879177, 0x5b0ed81dcc6abb0f, - 0x86ccbb52ea94baea, 0x98e947129fc2b4e9, - 0xa87fea27a539e9a5, 0x3f2398d747b36224, - 0xd29fe4b18e88640e, 0x8eec7f0d19a03aad, - 0x83a3eeeef9153e89, 0x1953cf68300424ac, - 0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd7, - 0xcdb02555653131b6, 0x3792f412cb06794d, - 0x808e17555f3ebf11, 0xe2bbd88bbee40bd0, - 0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec4, - 0xc8de047564d20a8b, 0xf245825a5a445275, - 0xfb158592be068d2e, 0xeed6e2f0f0d56712, - 0x9ced737bb6c4183d, 0x55464dd69685606b, - 0xc428d05aa4751e4c, 0xaa97e14c3c26b886, - 0xf53304714d9265df, 0xd53dd99f4b3066a8, - 0x993fe2c6d07b7fab, 0xe546a8038efe4029, - 0xbf8fdb78849a5f96, 0xde98520472bdd033, - 0xef73d256a5c0f77c, 0x963e66858f6d4440, - 0x95a8637627989aad, 0xdde7001379a44aa8, - 0xbb127c53b17ec159, 0x5560c018580d5d52, - 0xe9d71b689dde71af, 0xaab8f01e6e10b4a6, - 0x9226712162ab070d, 0xcab3961304ca70e8, - 0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d22, - 0xe45c10c42a2b3b05, 0x8cb89a7db77c506a, - 0x8eb98a7a9a5b04e3, 0x77f3608e92adb242, - 0xb267ed1940f1c61c, 0x55f038b237591ed3, - 0xdf01e85f912e37a3, 0x6b6c46dec52f6688, - 0x8b61313bbabce2c6, 0x2323ac4b3b3da015, - 0xae397d8aa96c1b77, 0xabec975e0a0d081a, - 0xd9c7dced53c72255, 0x96e7bd358c904a21, - 0x881cea14545c7575, 0x7e50d64177da2e54, - 0xaa242499697392d2, 0xdde50bd1d5d0b9e9, - 0xd4ad2dbfc3d07787, 0x955e4ec64b44e864, - 0x84ec3c97da624ab4, 0xbd5af13bef0b113e, - 0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58e, - 0xcfb11ead453994ba, 0x67de18eda5814af2, - 0x81ceb32c4b43fcf4, 0x80eacf948770ced7, - 0xa2425ff75e14fc31, 0xa1258379a94d028d, - 0xcad2f7f5359a3b3e, 0x96ee45813a04330, - 0xfd87b5f28300ca0d, 0x8bca9d6e188853fc, - 0x9e74d1b791e07e48, 0x775ea264cf55347e, - 0xc612062576589dda, 0x95364afe032a819e, - 0xf79687aed3eec551, 0x3a83ddbd83f52205, - 0x9abe14cd44753b52, 0xc4926a9672793543, - 0xc16d9a0095928a27, 0x75b7053c0f178294, - 0xf1c90080baf72cb1, 0x5324c68b12dd6339, - 0x971da05074da7bee, 0xd3f6fc16ebca5e04, - 0xbce5086492111aea, 0x88f4bb1ca6bcf585, - 0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6, - 0x9392ee8e921d5d07, 0x3aff322e62439fd0, - 0xb877aa3236a4b449, 0x9befeb9fad487c3, - 0xe69594bec44de15b, 0x4c2ebe687989a9b4, - 0x901d7cf73ab0acd9, 0xf9d37014bf60a11, - 0xb424dc35095cd80f, 0x538484c19ef38c95, - 0xe12e13424bb40e13, 0x2865a5f206b06fba, - 0x8cbccc096f5088cb, 0xf93f87b7442e45d4, - 0xafebff0bcb24aafe, 0xf78f69a51539d749, - 0xdbe6fecebdedd5be, 0xb573440e5a884d1c, - 0x89705f4136b4a597, 0x31680a88f8953031, - 0xabcc77118461cefc, 0xfdc20d2b36ba7c3e, - 0xd6bf94d5e57a42bc, 0x3d32907604691b4d, - 0x8637bd05af6c69b5, 0xa63f9a49c2c1b110, - 0xa7c5ac471b478423, 0xfcf80dc33721d54, - 0xd1b71758e219652b, 0xd3c36113404ea4a9, - 0x83126e978d4fdf3b, 0x645a1cac083126ea, - 0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4, - 0xcccccccccccccccc, 0xcccccccccccccccd, - 0x8000000000000000, 0x0, - 0xa000000000000000, 0x0, - 0xc800000000000000, 0x0, - 0xfa00000000000000, 0x0, - 0x9c40000000000000, 0x0, - 0xc350000000000000, 0x0, - 0xf424000000000000, 0x0, - 0x9896800000000000, 0x0, - 0xbebc200000000000, 0x0, - 0xee6b280000000000, 0x0, - 0x9502f90000000000, 0x0, - 0xba43b74000000000, 0x0, - 0xe8d4a51000000000, 0x0, - 0x9184e72a00000000, 0x0, - 0xb5e620f480000000, 0x0, - 0xe35fa931a0000000, 0x0, - 0x8e1bc9bf04000000, 0x0, - 0xb1a2bc2ec5000000, 0x0, - 0xde0b6b3a76400000, 0x0, - 0x8ac7230489e80000, 0x0, - 0xad78ebc5ac620000, 0x0, - 0xd8d726b7177a8000, 0x0, - 0x878678326eac9000, 0x0, - 0xa968163f0a57b400, 0x0, - 0xd3c21bcecceda100, 0x0, - 0x84595161401484a0, 0x0, - 0xa56fa5b99019a5c8, 0x0, - 0xcecb8f27f4200f3a, 0x0, - 0x813f3978f8940984, 0x4000000000000000, - 0xa18f07d736b90be5, 0x5000000000000000, - 0xc9f2c9cd04674ede, 0xa400000000000000, - 0xfc6f7c4045812296, 0x4d00000000000000, - 0x9dc5ada82b70b59d, 0xf020000000000000, - 0xc5371912364ce305, 0x6c28000000000000, - 0xf684df56c3e01bc6, 0xc732000000000000, - 0x9a130b963a6c115c, 0x3c7f400000000000, - 0xc097ce7bc90715b3, 0x4b9f100000000000, - 0xf0bdc21abb48db20, 0x1e86d40000000000, - 0x96769950b50d88f4, 0x1314448000000000, - 0xbc143fa4e250eb31, 0x17d955a000000000, - 0xeb194f8e1ae525fd, 0x5dcfab0800000000, - 0x92efd1b8d0cf37be, 0x5aa1cae500000000, - 0xb7abc627050305ad, 0xf14a3d9e40000000, - 0xe596b7b0c643c719, 0x6d9ccd05d0000000, - 0x8f7e32ce7bea5c6f, 0xe4820023a2000000, - 0xb35dbf821ae4f38b, 0xdda2802c8a800000, - 0xe0352f62a19e306e, 0xd50b2037ad200000, - 0x8c213d9da502de45, 0x4526f422cc340000, - 0xaf298d050e4395d6, 0x9670b12b7f410000, - 0xdaf3f04651d47b4c, 0x3c0cdd765f114000, - 0x88d8762bf324cd0f, 0xa5880a69fb6ac800, - 0xab0e93b6efee0053, 0x8eea0d047a457a00, - 0xd5d238a4abe98068, 0x72a4904598d6d880, - 0x85a36366eb71f041, 0x47a6da2b7f864750, - 0xa70c3c40a64e6c51, 0x999090b65f67d924, - 0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d, - 0x82818f1281ed449f, 0xbff8f10e7a8921a4, - 0xa321f2d7226895c7, 0xaff72d52192b6a0d, - 0xcbea6f8ceb02bb39, 0x9bf4f8a69f764490, - 0xfee50b7025c36a08, 0x2f236d04753d5b4, - 0x9f4f2726179a2245, 0x1d762422c946590, - 0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef5, - 0xf8ebad2b84e0d58b, 0xd2e0898765a7deb2, - 0x9b934c3b330c8577, 0x63cc55f49f88eb2f, - 0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fb, - 0xf316271c7fc3908a, 0x8bef464e3945ef7a, - 0x97edd871cfda3a56, 0x97758bf0e3cbb5ac, - 0xbde94e8e43d0c8ec, 0x3d52eeed1cbea317, - 0xed63a231d4c4fb27, 0x4ca7aaa863ee4bdd, - 0x945e455f24fb1cf8, 0x8fe8caa93e74ef6a, - 0xb975d6b6ee39e436, 0xb3e2fd538e122b44, - 0xe7d34c64a9c85d44, 0x60dbbca87196b616, - 0x90e40fbeea1d3a4a, 0xbc8955e946fe31cd, - 0xb51d13aea4a488dd, 0x6babab6398bdbe41, - 0xe264589a4dcdab14, 0xc696963c7eed2dd1, - 0x8d7eb76070a08aec, 0xfc1e1de5cf543ca2, - 0xb0de65388cc8ada8, 0x3b25a55f43294bcb, - 0xdd15fe86affad912, 0x49ef0eb713f39ebe, - 0x8a2dbf142dfcc7ab, 0x6e3569326c784337, - 0xacb92ed9397bf996, 0x49c2c37f07965404, - 0xd7e77a8f87daf7fb, 0xdc33745ec97be906, - 0x86f0ac99b4e8dafd, 0x69a028bb3ded71a3, - 0xa8acd7c0222311bc, 0xc40832ea0d68ce0c, - 0xd2d80db02aabd62b, 0xf50a3fa490c30190, - 0x83c7088e1aab65db, 0x792667c6da79e0fa, - 0xa4b8cab1a1563f52, 0x577001b891185938, - 0xcde6fd5e09abcf26, 0xed4c0226b55e6f86, - 0x80b05e5ac60b6178, 0x544f8158315b05b4, - 0xa0dc75f1778e39d6, 0x696361ae3db1c721, - 0xc913936dd571c84c, 0x3bc3a19cd1e38e9, - 0xfb5878494ace3a5f, 0x4ab48a04065c723, - 0x9d174b2dcec0e47b, 0x62eb0d64283f9c76, - 0xc45d1df942711d9a, 0x3ba5d0bd324f8394, - 0xf5746577930d6500, 0xca8f44ec7ee36479, - 0x9968bf6abbe85f20, 0x7e998b13cf4e1ecb, - 0xbfc2ef456ae276e8, 0x9e3fedd8c321a67e, - 0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101e, - 0x95d04aee3b80ece5, 0xbba1f1d158724a12, - 0xbb445da9ca61281f, 0x2a8a6e45ae8edc97, - 0xea1575143cf97226, 0xf52d09d71a3293bd, - 0x924d692ca61be758, 0x593c2626705f9c56, - 0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836c, - 0xe498f455c38b997a, 0xb6dfb9c0f956447, - 0x8edf98b59a373fec, 0x4724bd4189bd5eac, - 0xb2977ee300c50fe7, 0x58edec91ec2cb657, - 0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ed, - 0x8b865b215899f46c, 0xbd79e0d20082ee74, - 0xae67f1e9aec07187, 0xecd8590680a3aa11, - 0xda01ee641a708de9, 0xe80e6f4820cc9495, - 0x884134fe908658b2, 0x3109058d147fdcdd, - 0xaa51823e34a7eede, 0xbd4b46f0599fd415, - 0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91a, - 0x850fadc09923329e, 0x3e2cf6bc604ddb0, - 0xa6539930bf6bff45, 0x84db8346b786151c, - 0xcfe87f7cef46ff16, 0xe612641865679a63, - 0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07e, - 0xa26da3999aef7749, 0xe3be5e330f38f09d, - 0xcb090c8001ab551c, 0x5cadf5bfd3072cc5, - 0xfdcb4fa002162a63, 0x73d9732fc7c8f7f6, - 0x9e9f11c4014dda7e, 0x2867e7fddcdd9afa, - 0xc646d63501a1511d, 0xb281e1fd541501b8, - 0xf7d88bc24209a565, 0x1f225a7ca91a4226, - 0x9ae757596946075f, 0x3375788de9b06958, - 0xc1a12d2fc3978937, 0x52d6b1641c83ae, - 0xf209787bb47d6b84, 0xc0678c5dbd23a49a, - 0x9745eb4d50ce6332, 0xf840b7ba963646e0, - 0xbd176620a501fbff, 0xb650e5a93bc3d898, - 0xec5d3fa8ce427aff, 0xa3e51f138ab4cebe, - 0x93ba47c980e98cdf, 0xc66f336c36b10137, - 0xb8a8d9bbe123f017, 0xb80b0047445d4184, - 0xe6d3102ad96cec1d, 0xa60dc059157491e5, - 0x9043ea1ac7e41392, 0x87c89837ad68db2f, - 0xb454e4a179dd1877, 0x29babe4598c311fb, - 0xe16a1dc9d8545e94, 0xf4296dd6fef3d67a, - 0x8ce2529e2734bb1d, 0x1899e4a65f58660c, - 0xb01ae745b101e9e4, 0x5ec05dcff72e7f8f, - 0xdc21a1171d42645d, 0x76707543f4fa1f73, - 0x899504ae72497eba, 0x6a06494a791c53a8, - 0xabfa45da0edbde69, 0x487db9d17636892, - 0xd6f8d7509292d603, 0x45a9d2845d3c42b6, - 0x865b86925b9bc5c2, 0xb8a2392ba45a9b2, - 0xa7f26836f282b732, 0x8e6cac7768d7141e, - 0xd1ef0244af2364ff, 0x3207d795430cd926, - 0x8335616aed761f1f, 0x7f44e6bd49e807b8, - 0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a6, - 0xcd036837130890a1, 0x36dba887c37a8c0f, - 0x802221226be55a64, 0xc2494954da2c9789, - 0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6c, - 0xc83553c5c8965d3d, 0x6f92829494e5acc7, - 0xfa42a8b73abbf48c, 0xcb772339ba1f17f9, - 0x9c69a97284b578d7, 0xff2a760414536efb, - 0xc38413cf25e2d70d, 0xfef5138519684aba, - 0xf46518c2ef5b8cd1, 0x7eb258665fc25d69, - 0x98bf2f79d5993802, 0xef2f773ffbd97a61, - 0xbeeefb584aff8603, 0xaafb550ffacfd8fa, - 0xeeaaba2e5dbf6784, 0x95ba2a53f983cf38, - 0x952ab45cfa97a0b2, 0xdd945a747bf26183, - 0xba756174393d88df, 0x94f971119aeef9e4, - 0xe912b9d1478ceb17, 0x7a37cd5601aab85d, - 0x91abb422ccb812ee, 0xac62e055c10ab33a, - 0xb616a12b7fe617aa, 0x577b986b314d6009, - 0xe39c49765fdf9d94, 0xed5a7e85fda0b80b, - 0x8e41ade9fbebc27d, 0x14588f13be847307, - 0xb1d219647ae6b31c, 0x596eb2d8ae258fc8, - 0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bb, - 0x8aec23d680043bee, 0x25de7bb9480d5854, - 0xada72ccc20054ae9, 0xaf561aa79a10ae6a, - 0xd910f7ff28069da4, 0x1b2ba1518094da04, - 0x87aa9aff79042286, 0x90fb44d2f05d0842, - 0xa99541bf57452b28, 0x353a1607ac744a53, - 0xd3fa922f2d1675f2, 0x42889b8997915ce8, - 0x847c9b5d7c2e09b7, 0x69956135febada11, - 0xa59bc234db398c25, 0x43fab9837e699095, - 0xcf02b2c21207ef2e, 0x94f967e45e03f4bb, - 0x8161afb94b44f57d, 0x1d1be0eebac278f5, - 0xa1ba1ba79e1632dc, 0x6462d92a69731732, - 0xca28a291859bbf93, 0x7d7b8f7503cfdcfe, - 0xfcb2cb35e702af78, 0x5cda735244c3d43e, - 0x9defbf01b061adab, 0x3a0888136afa64a7, - 0xc56baec21c7a1916, 0x88aaa1845b8fdd0, - 0xf6c69a72a3989f5b, 0x8aad549e57273d45, - 0x9a3c2087a63f6399, 0x36ac54e2f678864b, - 0xc0cb28a98fcf3c7f, 0x84576a1bb416a7dd, - 0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d5, - 0x969eb7c47859e743, 0x9f644ae5a4b1b325, - 0xbc4665b596706114, 0x873d5d9f0dde1fee, - 0xeb57ff22fc0c7959, 0xa90cb506d155a7ea, - 0x9316ff75dd87cbd8, 0x9a7f12442d588f2, - 0xb7dcbf5354e9bece, 0xc11ed6d538aeb2f, - 0xe5d3ef282a242e81, 0x8f1668c8a86da5fa, - 0x8fa475791a569d10, 0xf96e017d694487bc, - 0xb38d92d760ec4455, 0x37c981dcc395a9ac, - 0xe070f78d3927556a, 0x85bbe253f47b1417, - 0x8c469ab843b89562, 0x93956d7478ccec8e, - 0xaf58416654a6babb, 0x387ac8d1970027b2, - 0xdb2e51bfe9d0696a, 0x6997b05fcc0319e, - 0x88fcf317f22241e2, 0x441fece3bdf81f03, - 0xab3c2fddeeaad25a, 0xd527e81cad7626c3, - 0xd60b3bd56a5586f1, 0x8a71e223d8d3b074, - 0x85c7056562757456, 0xf6872d5667844e49, - 0xa738c6bebb12d16c, 0xb428f8ac016561db, - 0xd106f86e69d785c7, 0xe13336d701beba52, - 0x82a45b450226b39c, 0xecc0024661173473, - 0xa34d721642b06084, 0x27f002d7f95d0190, - 0xcc20ce9bd35c78a5, 0x31ec038df7b441f4, - 0xff290242c83396ce, 0x7e67047175a15271, - 0x9f79a169bd203e41, 0xf0062c6e984d386, - 0xc75809c42c684dd1, 0x52c07b78a3e60868, - 0xf92e0c3537826145, 0xa7709a56ccdf8a82, - 0x9bbcc7a142b17ccb, 0x88a66076400bb691, - 0xc2abf989935ddbfe, 0x6acff893d00ea435, - 0xf356f7ebf83552fe, 0x583f6b8c4124d43, - 0x98165af37b2153de, 0xc3727a337a8b704a, - 0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5c, - 0xeda2ee1c7064130c, 0x1162def06f79df73, - 0x9485d4d1c63e8be7, 0x8addcb5645ac2ba8, - 0xb9a74a0637ce2ee1, 0x6d953e2bd7173692, - 0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0437, - 0x910ab1d4db9914a0, 0x1d9c9892400a22a2, - 0xb54d5e4a127f59c8, 0x2503beb6d00cab4b, - 0xe2a0b5dc971f303a, 0x2e44ae64840fd61d, - 0x8da471a9de737e24, 0x5ceaecfed289e5d2, - 0xb10d8e1456105dad, 0x7425a83e872c5f47, - 0xdd50f1996b947518, 0xd12f124e28f77719, - 0x8a5296ffe33cc92f, 0x82bd6b70d99aaa6f, - 0xace73cbfdc0bfb7b, 0x636cc64d1001550b, - 0xd8210befd30efa5a, 0x3c47f7e05401aa4e, - 0x8714a775e3e95c78, 0x65acfaec34810a71, - 0xa8d9d1535ce3b396, 0x7f1839a741a14d0d, - 0xd31045a8341ca07c, 0x1ede48111209a050, - 0x83ea2b892091e44d, 0x934aed0aab460432, - 0xa4e4b66b68b65d60, 0xf81da84d5617853f, - 0xce1de40642e3f4b9, 0x36251260ab9d668e, - 0x80d2ae83e9ce78f3, 0xc1d72b7c6b426019, - 0xa1075a24e4421730, 0xb24cf65b8612f81f, - 0xc94930ae1d529cfc, 0xdee033f26797b627, - 0xfb9b7cd9a4a7443c, 0x169840ef017da3b1, - 0x9d412e0806e88aa5, 0x8e1f289560ee864e, - 0xc491798a08a2ad4e, 0xf1a6f2bab92a27e2, - 0xf5b5d7ec8acb58a2, 0xae10af696774b1db, - 0x9991a6f3d6bf1765, 0xacca6da1e0a8ef29, - 0xbff610b0cc6edd3f, 0x17fd090a58d32af3, - 0xeff394dcff8a948e, 0xddfc4b4cef07f5b0, - 0x95f83d0a1fb69cd9, 0x4abdaf101564f98e, - 0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f1, - 0xea53df5fd18d5513, 0x84c86189216dc5ed, - 0x92746b9be2f8552c, 0x32fd3cf5b4e49bb4, - 0xb7118682dbb66a77, 0x3fbc8c33221dc2a1, - 0xe4d5e82392a40515, 0xfabaf3feaa5334a, - 0x8f05b1163ba6832d, 0x29cb4d87f2a7400e, - 0xb2c71d5bca9023f8, 0x743e20e9ef511012, - 0xdf78e4b2bd342cf6, 0x914da9246b255416, - 0x8bab8eefb6409c1a, 0x1ad089b6c2f7548e, - 0xae9672aba3d0c320, 0xa184ac2473b529b1, - 0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741e, - 0x8865899617fb1871, 0x7e2fa67c7a658892, - 0xaa7eebfb9df9de8d, 0xddbb901b98feeab7, - 0xd51ea6fa85785631, 0x552a74227f3ea565, - 0x8533285c936b35de, 0xd53a88958f87275f, - 0xa67ff273b8460356, 0x8a892abaf368f137, - 0xd01fef10a657842c, 0x2d2b7569b0432d85, - 0x8213f56a67f6b29b, 0x9c3b29620e29fc73, - 0xa298f2c501f45f42, 0x8349f3ba91b47b8f, - 0xcb3f2f7642717713, 0x241c70a936219a73, - 0xfe0efb53d30dd4d7, 0xed238cd383aa0110, - 0x9ec95d1463e8a506, 0xf4363804324a40aa, - 0xc67bb4597ce2ce48, 0xb143c6053edcd0d5, - 0xf81aa16fdc1b81da, 0xdd94b7868e94050a, - 0x9b10a4e5e9913128, 0xca7cf2b4191c8326, - 0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f0, - 0xf24a01a73cf2dccf, 0xbc633b39673c8cec, - 0x976e41088617ca01, 0xd5be0503e085d813, - 0xbd49d14aa79dbc82, 0x4b2d8644d8a74e18, - 0xec9c459d51852ba2, 0xddf8e7d60ed1219e, - 0x93e1ab8252f33b45, 0xcabb90e5c942b503, - 0xb8da1662e7b00a17, 0x3d6a751f3b936243, - 0xe7109bfba19c0c9d, 0xcc512670a783ad4, - 0x906a617d450187e2, 0x27fb2b80668b24c5, - 0xb484f9dc9641e9da, 0xb1f9f660802dedf6, - 0xe1a63853bbd26451, 0x5e7873f8a0396973, - 0x8d07e33455637eb2, 0xdb0b487b6423e1e8, - 0xb049dc016abc5e5f, 0x91ce1a9a3d2cda62, - 0xdc5c5301c56b75f7, 0x7641a140cc7810fb, - 0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9d, - 0xac2820d9623bf429, 0x546345fa9fbdcd44, - 0xd732290fbacaf133, 0xa97c177947ad4095, - 0x867f59a9d4bed6c0, 0x49ed8eabcccc485d, - 0xa81f301449ee8c70, 0x5c68f256bfff5a74, - 0xd226fc195c6a2f8c, 0x73832eec6fff3111, - 0x83585d8fd9c25db7, 0xc831fd53c5ff7eab, - 0xa42e74f3d032f525, 0xba3e7ca8b77f5e55, - 0xcd3a1230c43fb26f, 0x28ce1bd2e55f35eb, - 0x80444b5e7aa7cf85, 0x7980d163cf5b81b3, - 0xa0555e361951c366, 0xd7e105bcc332621f, - 0xc86ab5c39fa63440, 0x8dd9472bf3fefaa7, - 0xfa856334878fc150, 0xb14f98f6f0feb951, - 0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d3, - 0xc3b8358109e84f07, 0xa862f80ec4700c8, - 0xf4a642e14c6262c8, 0xcd27bb612758c0fa, - 0x98e7e9cccfbd7dbd, 0x8038d51cb897789c, - 0xbf21e44003acdd2c, 0xe0470a63e6bd56c3, - 0xeeea5d5004981478, 0x1858ccfce06cac74, - 0x95527a5202df0ccb, 0xf37801e0c43ebc8, - 0xbaa718e68396cffd, 0xd30560258f54e6ba, - 0xe950df20247c83fd, 0x47c6b82ef32a2069, - 0x91d28b7416cdd27e, 0x4cdc331d57fa5441, - 0xb6472e511c81471d, 0xe0133fe4adf8e952, - 0xe3d8f9e563a198e5, 0x58180fddd97723a6, - 0x8e679c2f5e44ff8f, 0x570f09eaa7ea7648 - }; - - private static void AccumulateDecimalDigitsIntoBigInteger(scoped ref NumberBuffer number, uint firstIndex, uint lastIndex, out BigInteger result) - { - BigInteger.SetZero(out result); - - byte* src = number.GetDigitsPointer() + firstIndex; - uint remaining = lastIndex - firstIndex; - - while (remaining != 0) - { - uint count = Math.Min(remaining, 9); - uint value = DigitsToUInt32(src, (int)(count)); - - result.MultiplyPow10(count); - result.Add(value); - - src += count; - remaining -= count; - } - } - - private static ulong AssembleFloatingPointBits(in FloatingPointInfo info, ulong initialMantissa, int initialExponent, bool hasZeroTail) - { - // number of bits by which we must adjust the mantissa to shift it into the - // correct position, and compute the resulting base two exponent for the - // normalized mantissa: - uint initialMantissaBits = BigInteger.CountSignificantBits(initialMantissa); - int normalMantissaShift = info.NormalMantissaBits - (int)(initialMantissaBits); - int normalExponent = initialExponent - normalMantissaShift; - - ulong mantissa = initialMantissa; - int exponent = normalExponent; - - if (normalExponent > info.MaxBinaryExponent) - { - // The exponent is too large to be represented by the floating point - // type; report the overflow condition: - return info.InfinityBits; - } - else if (normalExponent < info.MinBinaryExponent) - { - // The exponent is too small to be represented by the floating point - // type as a normal value, but it may be representable as a denormal - // value. Compute the number of bits by which we need to shift the - // mantissa in order to form a denormal number. (The subtraction of - // an extra 1 is to account for the hidden bit of the mantissa that - // is not available for use when representing a denormal.) - int denormalMantissaShift = normalMantissaShift + normalExponent + info.ExponentBias - 1; - - // Denormal values have an exponent of zero, so the debiased exponent is - // the negation of the exponent bias: - exponent = -info.ExponentBias; - - if (denormalMantissaShift < 0) - { - // Use two steps for right shifts: for a shift of N bits, we first - // shift by N-1 bits, then shift the last bit and use its value to - // round the mantissa. - mantissa = RightShiftWithRounding(mantissa, -denormalMantissaShift, hasZeroTail); - - // If the mantissa is now zero, we have underflowed: - if (mantissa == 0) - { - return info.ZeroBits; - } - - // When we round the mantissa, the result may be so large that the - // number becomes a normal value. For example, consider the single - // precision case where the mantissa is 0x01ffffff and a right shift - // of 2 is required to shift the value into position. We perform the - // shift in two steps: we shift by one bit, then we shift again and - // round using the dropped bit. The initial shift yields 0x00ffffff. - // The rounding shift then yields 0x007fffff and because the least - // significant bit was 1, we add 1 to this number to round it. The - // final result is 0x00800000. - // - // 0x00800000 is 24 bits, which is more than the 23 bits available - // in the mantissa. Thus, we have rounded our denormal number into - // a normal number. - // - // We detect this case here and re-adjust the mantissa and exponent - // appropriately, to form a normal number: - if (mantissa > info.DenormalMantissaMask) - { - // We add one to the denormalMantissaShift to account for the - // hidden mantissa bit (we subtracted one to account for this bit - // when we computed the denormalMantissaShift above). - exponent = initialExponent - (denormalMantissaShift + 1) - normalMantissaShift; - } - } - else - { - mantissa <<= denormalMantissaShift; - } - } - else - { - if (normalMantissaShift < 0) - { - // Use two steps for right shifts: for a shift of N bits, we first - // shift by N-1 bits, then shift the last bit and use its value to - // round the mantissa. - mantissa = RightShiftWithRounding(mantissa, -normalMantissaShift, hasZeroTail); - - // When we round the mantissa, it may produce a result that is too - // large. In this case, we divide the mantissa by two and increment - // the exponent (this does not change the value). - if (mantissa > info.NormalMantissaMask) - { - mantissa >>= 1; - exponent++; - - // The increment of the exponent may have generated a value too - // large to be represented. In this case, report the overflow: - if (exponent > info.MaxBinaryExponent) - { - return info.InfinityBits; - } - } - } - else if (normalMantissaShift > 0) - { - mantissa <<= normalMantissaShift; - } - } - - // Unset the hidden bit in the mantissa and assemble the floating point value - // from the computed components: - mantissa &= info.DenormalMantissaMask; - - Debug.Assert((info.DenormalMantissaMask & (1UL << info.DenormalMantissaBits)) == 0); - ulong shiftedExponent = ((ulong)(exponent + info.ExponentBias)) << info.DenormalMantissaBits; - Debug.Assert((shiftedExponent & info.DenormalMantissaMask) == 0); - Debug.Assert((mantissa & ~info.DenormalMantissaMask) == 0); - Debug.Assert((shiftedExponent & ~(((1UL << info.ExponentBits) - 1) << info.DenormalMantissaBits)) == 0); // exponent fits in its place - - return shiftedExponent | mantissa; - } - - private static ulong ConvertBigIntegerToFloatingPointBits(ref BigInteger value, in FloatingPointInfo info, uint integerBitsOfPrecision, bool hasNonZeroFractionalPart) - { - int baseExponent = info.DenormalMantissaBits; - - // When we have 64-bits or less of precision, we can just get the mantissa directly - if (integerBitsOfPrecision <= 64) - { - return AssembleFloatingPointBits(in info, value.ToUInt64(), baseExponent, !hasNonZeroFractionalPart); - } - - (uint topBlockIndex, uint topBlockBits) = Math.DivRem(integerBitsOfPrecision, 32); - uint middleBlockIndex = topBlockIndex - 1; - uint bottomBlockIndex = middleBlockIndex - 1; - - ulong mantissa; - int exponent = baseExponent + ((int)(bottomBlockIndex) * 32); - bool hasZeroTail = !hasNonZeroFractionalPart; - - // When the top 64-bits perfectly span two blocks, we can get those blocks directly - if (topBlockBits == 0) - { - mantissa = ((ulong)(value.GetBlock(middleBlockIndex)) << 32) + value.GetBlock(bottomBlockIndex); - } - else - { - // Otherwise, we need to read three blocks and combine them into a 64-bit mantissa - - int bottomBlockShift = (int)(topBlockBits); - int topBlockShift = 64 - bottomBlockShift; - int middleBlockShift = topBlockShift - 32; - - exponent += (int)(topBlockBits); - - uint bottomBlock = value.GetBlock(bottomBlockIndex); - uint bottomBits = bottomBlock >> bottomBlockShift; - - ulong middleBits = (ulong)(value.GetBlock(middleBlockIndex)) << middleBlockShift; - ulong topBits = (ulong)(value.GetBlock(topBlockIndex)) << topBlockShift; - - mantissa = topBits + middleBits + bottomBits; - - uint unusedBottomBlockBitsMask = (1u << (int)(topBlockBits)) - 1; - hasZeroTail &= (bottomBlock & unusedBottomBlockBitsMask) == 0; - } - - for (uint i = 0; i != bottomBlockIndex; i++) - { - hasZeroTail &= (value.GetBlock(i) == 0); - } - - return AssembleFloatingPointBits(in info, mantissa, exponent, hasZeroTail); - } - - // get 32-bit integer from at most 9 digits - private static uint DigitsToUInt32(byte* p, int count) - { - Debug.Assert((1 <= count) && (count <= 9)); - - byte* end = (p + count); - uint res = 0; - - // parse batches of 8 digits with SWAR - while (p <= end - 8) - { - res = (res * 100000000) + ParseEightDigitsUnrolled(p); - p += 8; - } - - while (p != end) - { - res = (10 * res) + p[0] - '0'; - ++p; - } - - return res; - } - - // get 64-bit integer from at most 19 digits - private static ulong DigitsToUInt64(byte* p, int count) - { - Debug.Assert((1 <= count) && (count <= 19)); - - byte* end = (p + count); - ulong res = 0; - - // parse batches of 8 digits with SWAR - while (end - p >= 8) - { - res = (res * 100000000) + ParseEightDigitsUnrolled(p); - p += 8; - } - - while (p != end) - { - res = (10 * res) + p[0] - '0'; - ++p; - } - - return res; - } - - /// - /// Parse eight consecutive digits using SWAR - /// https://lemire.me/blog/2022/01/21/swar-explained-parsing-eight-digits/ - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static uint ParseEightDigitsUnrolled(byte* chars) - { - // let's take the following value (byte*) 12345678 and read it unaligned : - // we get a ulong value of 0x3837363534333231 - // 1. Subtract character '0' 0x30 for each byte to get 0x0807060504030201 - // 2. Consider this sequence as bytes sequence : b8b7b6b5b4b3b2b1 - // we need to transform it to b1b2b3b4b5b6b7b8 by computing : - // 10000 * (100 * (10*b1+b2) + 10*b3+b4) + 100*(10*b5+b6) + 10*b7+b8 - // this is achieved by masking and shifting values - ulong val = Unsafe.ReadUnaligned(chars); - - // With BigEndian system an endianness swap has to be performed - // before the following operations as if it has been read with LittleEndian system - if (!BitConverter.IsLittleEndian) - { - val = BinaryPrimitives.ReverseEndianness(val); - } - - const ulong mask = 0x000000FF000000FF; - const ulong mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32) - const ulong mul2 = 0x0000271000000001; // 1 + (10000ULL << 32) - val -= 0x3030303030303030; - val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8; - val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32; - return (uint)val; - } - - private static ulong NumberToDoubleFloatingPointBits(ref NumberBuffer number, in FloatingPointInfo info) - { - Debug.Assert(info.DenormalMantissaBits == 52); - - Debug.Assert(number.GetDigitsPointer()[0] != '0'); - - Debug.Assert(number.Scale <= FloatingPointMaxExponent); - Debug.Assert(number.Scale >= FloatingPointMinExponent); - - Debug.Assert(number.DigitsCount != 0); - - // The input is of the form 0.Mantissa x 10^Exponent, where 'Mantissa' are - // the decimal digits of the mantissa and 'Exponent' is the decimal exponent. - // We decompose the mantissa into two parts: an integer part and a fractional - // part. If the exponent is positive, then the integer part consists of the - // first 'exponent' digits, or all present digits if there are fewer digits. - // If the exponent is zero or negative, then the integer part is empty. In - // either case, the remaining digits form the fractional part of the mantissa. - - uint totalDigits = (uint)(number.DigitsCount); - uint positiveExponent = (uint)(Math.Max(0, number.Scale)); - - uint integerDigitsPresent = Math.Min(positiveExponent, totalDigits); - uint fractionalDigitsPresent = totalDigits - integerDigitsPresent; - - // Above 19 digits, we rely on slow path - if (totalDigits <= 19) - { - byte* src = number.GetDigitsPointer(); - - ulong mantissa = DigitsToUInt64(src, (int)(totalDigits)); - - int exponent = (int)(number.Scale - integerDigitsPresent - fractionalDigitsPresent); - int fastExponent = Math.Abs(exponent); - - // When the number of significant digits is less than or equal to MaxMantissaFastPath and the - // scale is less than or equal to MaxExponentFastPath, we can take some shortcuts and just rely - // on floating-point arithmetic to compute the correct result. This is - // because each floating-point precision values allows us to exactly represent - // different whole integers and certain powers of 10, depending on the underlying - // formats exact range. Additionally, IEEE operations dictate that the result is - // computed to the infinitely precise result and then rounded, which means that - // we can rely on it to produce the correct result when both inputs are exact. - // This is known as Clinger's fast path - - if ((mantissa <= info.MaxMantissaFastPath) && (fastExponent <= info.MaxExponentFastPath)) - { - double mantissa_d = mantissa; - double scale = s_Pow10DoubleTable[fastExponent]; - - if (fractionalDigitsPresent != 0) - { - mantissa_d /= scale; - } - else - { - mantissa_d *= scale; - } - - return BitConverter.DoubleToUInt64Bits(mantissa_d); - } - - // Number Parsing at a Gigabyte per Second, Software: Practice and Experience 51(8), 2021 - // https://arxiv.org/abs/2101.11408 - (int Exponent, ulong Mantissa) am = ComputeFloat(exponent, mantissa, info); - - // If we called ComputeFloat and we have an invalid power of 2 (Exponent < 0), - // then we need to go the slow way around again. This is very uncommon. - if (am.Exponent > 0) - { - ulong word = am.Mantissa; - word |= (ulong)(uint)(am.Exponent) << info.DenormalMantissaBits; - return word; - - } - } - - return NumberToFloatingPointBitsSlow(ref number, in info, positiveExponent, integerDigitsPresent, fractionalDigitsPresent); - } - - private static ushort NumberToHalfFloatingPointBits(ref NumberBuffer number, in FloatingPointInfo info) - { - Debug.Assert(info.DenormalMantissaBits == 10); - - Debug.Assert(number.GetDigitsPointer()[0] != '0'); - - Debug.Assert(number.Scale <= FloatingPointMaxExponent); - Debug.Assert(number.Scale >= FloatingPointMinExponent); - - Debug.Assert(number.DigitsCount != 0); - - // The input is of the form 0.Mantissa x 10^Exponent, where 'Mantissa' are - // the decimal digits of the mantissa and 'Exponent' is the decimal exponent. - // We decompose the mantissa into two parts: an integer part and a fractional - // part. If the exponent is positive, then the integer part consists of the - // first 'exponent' digits, or all present digits if there are fewer digits. - // If the exponent is zero or negative, then the integer part is empty. In - // either case, the remaining digits form the fractional part of the mantissa. - - uint totalDigits = (uint)(number.DigitsCount); - uint positiveExponent = (uint)(Math.Max(0, number.Scale)); - - uint integerDigitsPresent = Math.Min(positiveExponent, totalDigits); - uint fractionalDigitsPresent = totalDigits - integerDigitsPresent; - - int exponent = (int)(number.Scale - integerDigitsPresent - fractionalDigitsPresent); - int fastExponent = Math.Abs(exponent); - - // Above 19 digits, we rely on slow path - if (totalDigits <= 19) - { - byte* src = number.GetDigitsPointer(); - - // When the number of significant digits is less than or equal to MaxMantissaFastPath and the - // scale is less than or equal to MaxExponentFastPath, we can take some shortcuts and just rely - // on floating-point arithmetic to compute the correct result. This is - // because each floating-point precision values allows us to exactly represent - // different whole integers and certain powers of 10, depending on the underlying - // formats exact range. Additionally, IEEE operations dictate that the result is - // computed to the infinitely precise result and then rounded, which means that - // we can rely on it to produce the correct result when both inputs are exact. - // This is known as Clinger's fast path - - ulong mantissa = DigitsToUInt64(src, (int)(totalDigits)); - - if ((mantissa <= info.MaxMantissaFastPath) && (fastExponent <= info.MaxExponentFastPath)) - { - double mantissa_d = mantissa; - double scale = s_Pow10DoubleTable[fastExponent]; - - if (fractionalDigitsPresent != 0) - { - mantissa_d /= scale; - } - else - { - mantissa_d *= scale; - } - - return BitConverter.HalfToUInt16Bits((Half)(mantissa_d)); - } - - // Number Parsing at a Gigabyte per Second, Software: Practice and Experience 51(8), 2021 - // https://arxiv.org/abs/2101.11408 - (int Exponent, ulong Mantissa) am = ComputeFloat(exponent, mantissa, info); - - // If we called ComputeFloat and we have an invalid power of 2 (Exponent < 0), - // then we need to go the slow way around again. This is very uncommon. - if (am.Exponent > 0) - { - ulong word = am.Mantissa; - word |= (ulong)(uint)(am.Exponent) << info.DenormalMantissaBits; - return (ushort)word; - } - - } - return (ushort)NumberToFloatingPointBitsSlow(ref number, in info, positiveExponent, integerDigitsPresent, fractionalDigitsPresent); - } - - private static uint NumberToSingleFloatingPointBits(ref NumberBuffer number, in FloatingPointInfo info) - { - Debug.Assert(info.DenormalMantissaBits == 23); - - Debug.Assert(number.GetDigitsPointer()[0] != '0'); - - Debug.Assert(number.Scale <= FloatingPointMaxExponent); - Debug.Assert(number.Scale >= FloatingPointMinExponent); - - Debug.Assert(number.DigitsCount != 0); - - // The input is of the form 0.Mantissa x 10^Exponent, where 'Mantissa' are - // the decimal digits of the mantissa and 'Exponent' is the decimal exponent. - // We decompose the mantissa into two parts: an integer part and a fractional - // part. If the exponent is positive, then the integer part consists of the - // first 'exponent' digits, or all present digits if there are fewer digits. - // If the exponent is zero or negative, then the integer part is empty. In - // either case, the remaining digits form the fractional part of the mantissa. - - uint totalDigits = (uint)(number.DigitsCount); - uint positiveExponent = (uint)(Math.Max(0, number.Scale)); - - uint integerDigitsPresent = Math.Min(positiveExponent, totalDigits); - uint fractionalDigitsPresent = totalDigits - integerDigitsPresent; - - int exponent = (int)(number.Scale - integerDigitsPresent - fractionalDigitsPresent); - int fastExponent = Math.Abs(exponent); - - - // Above 19 digits, we rely on slow path - if (totalDigits <= 19) - { - - byte* src = number.GetDigitsPointer(); - - // When the number of significant digits is less than or equal to MaxMantissaFastPath and the - // scale is less than or equal to MaxExponentFastPath, we can take some shortcuts and just rely - // on floating-point arithmetic to compute the correct result. This is - // because each floating-point precision values allows us to exactly represent - // different whole integers and certain powers of 10, depending on the underlying - // formats exact range. Additionally, IEEE operations dictate that the result is - // computed to the infinitely precise result and then rounded, which means that - // we can rely on it to produce the correct result when both inputs are exact. - // This is known as Clinger's fast path - - ulong mantissa = DigitsToUInt64(src, (int)(totalDigits)); - - if ((mantissa <= info.MaxMantissaFastPath) && (fastExponent <= info.MaxExponentFastPath)) - { - double mantissa_d = mantissa; - double scale = s_Pow10DoubleTable[fastExponent]; - - if (fractionalDigitsPresent != 0) - { - mantissa_d /= scale; - } - else - { - mantissa_d *= scale; - } - - return BitConverter.SingleToUInt32Bits((float)(mantissa_d)); - } - - // Number Parsing at a Gigabyte per Second, Software: Practice and Experience 51(8), 2021 - // https://arxiv.org/abs/2101.11408 - (int Exponent, ulong Mantissa) am = ComputeFloat(exponent, mantissa, info); - - // If we called ComputeFloat and we have an invalid power of 2 (Exponent < 0), - // then we need to go the slow way around again. This is very uncommon. - if (am.Exponent > 0) - { - ulong word = am.Mantissa; - word |= (ulong)(uint)(am.Exponent) << info.DenormalMantissaBits; - return (uint)word; - } - } - return (uint)NumberToFloatingPointBitsSlow(ref number, in info, positiveExponent, integerDigitsPresent, fractionalDigitsPresent); - } - - private static ulong NumberToFloatingPointBitsSlow(ref NumberBuffer number, in FloatingPointInfo info, uint positiveExponent, uint integerDigitsPresent, uint fractionalDigitsPresent) - { - // To generate an N bit mantissa we require N + 1 bits of precision. The - // extra bit is used to correctly round the mantissa (if there are fewer bits - // than this available, then that's totally okay; in that case we use what we - // have and we don't need to round). - uint requiredBitsOfPrecision = (uint)(info.NormalMantissaBits + 1); - - uint totalDigits = (uint)(number.DigitsCount); - uint integerDigitsMissing = positiveExponent - integerDigitsPresent; - - const uint IntegerFirstIndex = 0; - uint integerLastIndex = integerDigitsPresent; - - uint fractionalFirstIndex = integerLastIndex; - uint fractionalLastIndex = totalDigits; - - // First, we accumulate the integer part of the mantissa into a BigInteger: - AccumulateDecimalDigitsIntoBigInteger(ref number, IntegerFirstIndex, integerLastIndex, out BigInteger integerValue); - - if (integerDigitsMissing > 0) - { - if (integerDigitsMissing > info.OverflowDecimalExponent) - { - return info.InfinityBits; - } - - integerValue.MultiplyPow10(integerDigitsMissing); - } - - // At this point, the integerValue contains the value of the integer part - // of the mantissa. If either [1] this number has more than the required - // number of bits of precision or [2] the mantissa has no fractional part, - // then we can assemble the result immediately: - uint integerBitsOfPrecision = BigInteger.CountSignificantBits(ref integerValue); - - if ((integerBitsOfPrecision >= requiredBitsOfPrecision) || (fractionalDigitsPresent == 0)) - { - return ConvertBigIntegerToFloatingPointBits( - ref integerValue, - in info, - integerBitsOfPrecision, - fractionalDigitsPresent != 0 - ); - } - - // Otherwise, we did not get enough bits of precision from the integer part, - // and the mantissa has a fractional part. We parse the fractional part of - // the mantissa to obtain more bits of precision. To do this, we convert - // the fractional part into an actual fraction N/M, where the numerator N is - // computed from the digits of the fractional part, and the denominator M is - // computed as the power of 10 such that N/M is equal to the value of the - // fractional part of the mantissa. - - uint fractionalDenominatorExponent = fractionalDigitsPresent; - - if (number.Scale < 0) - { - fractionalDenominatorExponent += (uint)(-number.Scale); - } - - if ((integerBitsOfPrecision == 0) && (fractionalDenominatorExponent - (int)(totalDigits)) > info.OverflowDecimalExponent) - { - // If there were any digits in the integer part, it is impossible to - // underflow (because the exponent cannot possibly be small enough), - // so if we underflow here it is a true underflow and we return zero. - return info.ZeroBits; - } - - AccumulateDecimalDigitsIntoBigInteger(ref number, fractionalFirstIndex, fractionalLastIndex, out BigInteger fractionalNumerator); - - if (fractionalNumerator.IsZero()) - { - return ConvertBigIntegerToFloatingPointBits( - ref integerValue, - in info, - integerBitsOfPrecision, - fractionalDigitsPresent != 0 - ); - } - - BigInteger.Pow10(fractionalDenominatorExponent, out BigInteger fractionalDenominator); - - // Because we are using only the fractional part of the mantissa here, the - // numerator is guaranteed to be smaller than the denominator. We normalize - // the fraction such that the most significant bit of the numerator is in - // the same position as the most significant bit in the denominator. This - // ensures that when we later shift the numerator N bits to the left, we - // will produce N bits of precision. - uint fractionalNumeratorBits = BigInteger.CountSignificantBits(ref fractionalNumerator); - uint fractionalDenominatorBits = BigInteger.CountSignificantBits(ref fractionalDenominator); - - uint fractionalShift = 0; - - if (fractionalDenominatorBits > fractionalNumeratorBits) - { - fractionalShift = fractionalDenominatorBits - fractionalNumeratorBits; - } - - if (fractionalShift > 0) - { - fractionalNumerator.ShiftLeft(fractionalShift); - } - - uint requiredFractionalBitsOfPrecision = requiredBitsOfPrecision - integerBitsOfPrecision; - uint remainingBitsOfPrecisionRequired = requiredFractionalBitsOfPrecision; - - if (integerBitsOfPrecision > 0) - { - // If the fractional part of the mantissa provides no bits of precision - // and cannot affect rounding, we can just take whatever bits we got from - // the integer part of the mantissa. This is the case for numbers like - // 5.0000000000000000000001, where the significant digits of the fractional - // part start so far to the right that they do not affect the floating - // point representation. - // - // If the fractional shift is exactly equal to the number of bits of - // precision that we require, then no fractional bits will be part of the - // result, but the result may affect rounding. This is e.g. the case for - // large, odd integers with a fractional part greater than or equal to .5. - // Thus, we need to do the division to correctly round the result. - if (fractionalShift > remainingBitsOfPrecisionRequired) - { - return ConvertBigIntegerToFloatingPointBits( - ref integerValue, - in info, - integerBitsOfPrecision, - fractionalDigitsPresent != 0 - ); - } - - remainingBitsOfPrecisionRequired -= fractionalShift; - } - - // If there was no integer part of the mantissa, we will need to compute the - // exponent from the fractional part. The fractional exponent is the power - // of two by which we must multiply the fractional part to move it into the - // range [1.0, 2.0). This will either be the same as the shift we computed - // earlier, or one greater than that shift: - uint fractionalExponent = fractionalShift; - - if (BigInteger.Compare(ref fractionalNumerator, ref fractionalDenominator) < 0) - { - fractionalExponent++; - } - - fractionalNumerator.ShiftLeft(remainingBitsOfPrecisionRequired); - - BigInteger.DivRem(ref fractionalNumerator, ref fractionalDenominator, out BigInteger bigFractionalMantissa, out BigInteger fractionalRemainder); - ulong fractionalMantissa = bigFractionalMantissa.ToUInt64(); - bool hasZeroTail = !number.HasNonZeroTail && fractionalRemainder.IsZero(); - - // We may have produced more bits of precision than were required. Check, - // and remove any "extra" bits: - uint fractionalMantissaBits = BigInteger.CountSignificantBits(fractionalMantissa); - - if (fractionalMantissaBits > requiredFractionalBitsOfPrecision) - { - int shift = (int)(fractionalMantissaBits - requiredFractionalBitsOfPrecision); - hasZeroTail = hasZeroTail && (fractionalMantissa & ((1UL << shift) - 1)) == 0; - fractionalMantissa >>= shift; - } - - // Compose the mantissa from the integer and fractional parts: - ulong integerMantissa = integerValue.ToUInt64(); - ulong completeMantissa = (integerMantissa << (int)(requiredFractionalBitsOfPrecision)) + fractionalMantissa; - - // Compute the final exponent: - // * If the mantissa had an integer part, then the exponent is one less than - // the number of bits we obtained from the integer part. (It's one less - // because we are converting to the form 1.11111, with one 1 to the left - // of the decimal point.) - // * If the mantissa had no integer part, then the exponent is the fractional - // exponent that we computed. - // Then, in both cases, we subtract an additional one from the exponent, to - // account for the fact that we've generated an extra bit of precision, for - // use in rounding. - int finalExponent = (integerBitsOfPrecision > 0) ? (int)(integerBitsOfPrecision) - 2 : -(int)(fractionalExponent) - 1; - - return AssembleFloatingPointBits(in info, completeMantissa, finalExponent, hasZeroTail); - } - - private static ulong RightShiftWithRounding(ulong value, int shift, bool hasZeroTail) - { - // If we'd need to shift further than it is possible to shift, the answer - // is always zero: - if (shift >= 64) - { - return 0; - } - - ulong extraBitsMask = (1UL << (shift - 1)) - 1; - ulong roundBitMask = (1UL << (shift - 1)); - ulong lsbBitMask = 1UL << shift; - - bool lsbBit = (value & lsbBitMask) != 0; - bool roundBit = (value & roundBitMask) != 0; - bool hasTailBits = !hasZeroTail || (value & extraBitsMask) != 0; - - return (value >> shift) + (ShouldRoundUp(lsbBit, roundBit, hasTailBits) ? 1UL : 0); - } - - private static bool ShouldRoundUp(bool lsbBit, bool roundBit, bool hasTailBits) - { - // If there are insignificant set bits, we need to round to the - // nearest; there are two cases: - // we round up if either [1] the value is slightly greater than the midpoint - // between two exactly representable values or [2] the value is exactly the - // midpoint between two exactly representable values and the greater of the - // two is even (this is "round-to-even"). - return roundBit && (hasTailBits || lsbBit); - } - - - /// - /// Daniel Lemire's Fast-float algorithm please refer to https://arxiv.org/abs/2101.11408 - /// Ojective is to calculate m and p, adjusted mantissa and power of 2, based on the - /// following equality : (m x 2^p) = (w x 10^q) - /// - /// decimal exponent - /// decimal significant (mantissa) - /// parameters for calculations for the value's type (double, float, half) - /// Tuple : Exponent (power of 2) and adjusted mantissa - internal static (int Exponent, ulong Mantissa) ComputeFloat(long q, ulong w, FloatingPointInfo info) - { - int exponent; - ulong mantissa = 0; - - if ((w == 0) || (q < info.MinFastFloatDecimalExponent)) - { - // result should be zero - return default; - } - if (q > info.MaxFastFloatDecimalExponent) - { - // we want to get infinity: - exponent = info.InfinityExponent; - mantissa = 0; - return (exponent, mantissa); - } - - // We want the most significant bit of i to be 1. Shift if needed. - int lz = BitOperations.LeadingZeroCount(w); - w <<= lz; - - // The required precision is info.DenormalMantissaBits + 3 because - // 1. We need the implicit bit - // 2. We need an extra bit for rounding purposes - // 3. We might lose a bit due to the "upperbit" routine (result too small, requiring a shift) - - var product = ComputeProductApproximation(info.DenormalMantissaBits + 3, q, w); - if (product.low == 0xFFFFFFFFFFFFFFFF) - { - // could guard it further - // In some very rare cases, this could happen, in which case we might need a more accurate - // computation that what we can provide cheaply. This is very, very unlikely. - // - bool insideSafeExponent = (q >= -27) && (q <= 55); // always good because 5**q <2**128 when q>=0, - // and otherwise, for q<0, we have 5**-q<2**64 and the 128-bit reciprocal allows for exact computation. - if (!insideSafeExponent) - { - exponent = -1; // This (a negative value) indicates an error condition. - return (exponent, mantissa); - } - } - // The "ComputeProductApproximation" function can be slightly slower than a branchless approach: - // but in practice, we can win big with the ComputeProductApproximation if its additional branch - // is easily predicted. Which is best is data specific. - int upperBit = (int)(product.high >> 63); - - mantissa = product.high >> (upperBit + 64 - info.DenormalMantissaBits - 3); - - exponent = (int)(CalculatePower((int)(q)) + upperBit - lz - (-info.MaxBinaryExponent)); - if (exponent <= 0) - { - // we have a subnormal? - // Here have that answer.power2 <= 0 so -answer.power2 >= 0 - if (-exponent + 1 >= 64) - { - // if we have more than 64 bits below the minimum exponent, you have a zero for sure. - exponent = 0; - mantissa = 0; - // result should be zero - return (exponent, mantissa); - } - // next line is safe because -answer.power2 + 1 < 64 - mantissa >>= -exponent + 1; - // Thankfully, we can't have both "round-to-even" and subnormals because - // "round-to-even" only occurs for powers close to 0. - mantissa += (mantissa & 1); // round up - mantissa >>= 1; - // There is a weird scenario where we don't have a subnormal but just - // suppose we start with 2.2250738585072013e-308, we end up - // with 0x3fffffffffffff x 2^-1023-53 which is technically subnormal - // whereas 0x40000000000000 x 2^-1023-53 is normal. Now, we need to round - // up 0x3fffffffffffff x 2^-1023-53 and once we do, we are no longer - // subnormal, but we can only know this after rounding. - // So we only declare a subnormal if we are smaller than the threshold. - exponent = (mantissa < (1UL << info.DenormalMantissaBits)) ? 0 : 1; - return (exponent, mantissa); - } - - // usually, we round *up*, but if we fall right in between and and we have an - // even basis, we need to round down - // We are only concerned with the cases where 5**q fits in single 64-bit word. - if ((product.low <= 1) && (q >= info.MinExponentRoundToEven) && (q <= info.MaxExponentRoundToEven) && - ((mantissa & 3) == 1)) - { - // We may fall between two floats! - // To be in-between two floats we need that in doing - // answer.mantissa = product.high >> (upperBit + 64 - info.DenormalMantissaBits - 3); - // ... we dropped out only zeroes. But if this happened, then we can go back!!! - if ((mantissa << (upperBit + 64 - info.DenormalMantissaBits - 3)) == product.high) - { - // flip it so that we do not round up - mantissa &= ~1UL; - } - } - - mantissa += (mantissa & 1); // round up - mantissa >>= 1; - if (mantissa >= (2UL << info.DenormalMantissaBits)) - { - mantissa = (1UL << info.DenormalMantissaBits); - // undo previous addition - exponent++; - } - - mantissa &= ~(1UL << info.DenormalMantissaBits); - if (exponent >= info.InfinityExponent) - { - // infinity - exponent = info.InfinityExponent; - mantissa = 0; - } - return (exponent, mantissa); - } - private static (ulong high, ulong low) ComputeProductApproximation(int bitPrecision, long q, ulong w) - { - // -342 being the SmallestPowerOfFive - int index = 2 * (int)(q - -342); - // For small values of q, e.g., q in [0,27], the answer is always exact because - // Math.BigMul gives the exact answer. - ulong high = Math.BigMul(w, s_Pow5128Table[index], out ulong low); - ulong precisionMask = (bitPrecision < 64) ? (0xFFFFFFFFFFFFFFFFUL >> bitPrecision) : 0xFFFFFFFFFFFFFFFFUL; - if ((high & precisionMask) == precisionMask) - { - // could further guard with (lower + w < lower) - // regarding the second product, we only need secondproduct.high, but our expectation is that the compiler will optimize this extra work away if needed. - ulong high2 = Math.BigMul(w, s_Pow5128Table[index + 1], out ulong _); - low += high2; - if (high2 > low) - { - high++; - } - } - return (high, low); - } - - // For q in (0,350), we have that : - // f = (((152170 + 65536) * q) >> 16); - // is equal to - // floor(p) + q - // where - // p = log(5**q)/log(2) = q* log(5)/log(2) - // - // For negative values of q in (-400,0), we have that - // f = (((152170 + 65536) * q) >> 16); - // is equal to : - // -ceil(p) + q - // where - // p = log(5**-q)/log(2) = -q* log(5)/log(2) - // - internal static int CalculatePower(int q) - => (((152170 + 65536) * q) >> 16) + 63; - } -} diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs index c9fb41509e1f6a..9159d1a8d5c1f5 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs @@ -35,7 +35,7 @@ internal static partial class IeeeDecimalNumber { // IeeeDecimalNumberBuffer - internal const int Decimal32BufferLength = 0 + 1 + 1; // TODO: X for the longest input + 1 for rounding (+1 for the null terminator) + internal const int Decimal32BufferLength = 112 + 1 + 1; // TODO: X for the longest input + 1 for rounding (+1 for the null terminator). I just picked 112 cause that's what Single does for now. internal unsafe ref struct IeeeDecimalNumberBuffer { @@ -70,10 +70,10 @@ public IeeeDecimalNumberBuffer(Span digits) #pragma warning disable CA1822 [Conditional("DEBUG")] - public void CheckConsistency() // TODO do we want this? + public void CheckConsistency() { #if DEBUG - Debug.Assert(Digits[0] != '0', "Leading zeros should never be stored in a IeeeDecimalNumber"); + Debug.Assert(Digits[0] != '0', "Leading zeros should never be stored in an IeeeDecimalNumber"); int numDigits; for (numDigits = 0; numDigits < Digits.Length; numDigits++) @@ -135,8 +135,9 @@ public override string ToString() } } - // IeeeDecimalNumber Parsing TODO potentially rewrite this description + // IeeeDecimalNumber Parsing + // TODO potentially rewrite this description // The Parse methods provided by the numeric classes convert a // string to a numeric value. The optional style parameter specifies the // permitted style of the numeric string. It must be a combination of bit flags @@ -148,10 +149,15 @@ public override string ToString() // Numeric strings produced by the Format methods using the Currency, // Decimal, Engineering, Fixed point, General, or Number standard formats // (the C, D, E, F, G, and N format specifiers) are guaranteed to be parseable - // by the Parse methods if the NumberStyles.Any style is + // by the Parse methods if the NumberStyles. Any style is // specified. Note, however, that the Parse methods do not accept // NaNs or Infinities. + + // Max and Min Exponent assuming the value is in the form 0.Mantissa x 10^Exponent + private const int Decimal32MaxExponent = Decimal32.MaxQExponent + Decimal32.Precision; // TODO check this + private const int Decimal32MinExponent = Decimal32.MinQExponent + Decimal32.Precision; // TODO check this, probably wrong + [DoesNotReturn] internal static void ThrowFormatException(ParsingStatus status, ReadOnlySpan value, TypeCode type = 0) => throw new FormatException(SR.Format(SR.Format_InvalidStringWithValue, value.ToString())); @@ -572,70 +578,109 @@ private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, Nu internal static unsafe Decimal32 NumberToDecimal32(ref IeeeDecimalNumberBuffer number) { number.CheckConsistency(); - //Decimal32 result; - return default; // TODO figure this out after formatting - - // The input value is of the form 0.Mantissa x 10^Exponent, where 'Mantissa' are - // the decimal digits of the mantissa and 'Exponent' is the decimal exponent. - // We want to extract q (the exponent) and c (the significand) such that - // value = c * 10 ^ q - // Which means - // c = first N digits of Mantissa, where N is min(Decimal32.Precision, number.DigitsCount) - // - Note: If there are more than Decimal32.Precision digits in the number, we must round - // q = Exponent - N - // - Note: If Exponent - N cannot fit in q we need to adjust c and round - // Step 1: Adjust the exponent such that the value Mantissa.ExtraDigits x 10^Exponent -/* int q = number.Scale - 7; - - - if ((number.DigitsCount == 0) || ((q < Decimal32.MinQExponent) && number.DigitsCount)) + if ((number.DigitsCount == 0) || (number.Scale < Decimal32MinExponent)) // TODO double check this { - result = default; // TODO are we sure this is the "right" zero to return in all these cases + // TODO are we sure this is the "right" zero to return in all these cases + return number.IsNegative ? Decimal32.NegativeZero : Decimal32.Zero; } - else if (q > Decimal32.MaxQExponent) + else if (number.Scale > Decimal32MaxExponent) // TODO double check this { - result = Decimal32.PositiveInfinity; + return number.IsNegative ? Decimal32.NegativeInfinity : Decimal32.PositiveInfinity; } else { - - - // Step 1: Adjust + // The input value is of the form 0.Mantissa x 10^Exponent, where 'Mantissa' are + // the decimal digits of the mantissa and 'Exponent' is the decimal exponent. + // We want to extract q (the exponent) and c (the significand) such that + // value = c * 10 ^ q + // Which means + // c = first N digits of Mantissa, where N is min(Decimal32.Precision, number.DigitsCount) + // q = Exponent - N byte* mantissa = number.GetDigitsPointer(); - int exponent = number.Scale; - uint digit = *mantissa; + int q = number.Scale; + byte* mantissaPointer = number.GetDigitsPointer(); + uint c = 0; - uint digitsToExtract; - bool needToRound; - if (number.DigitsCount > Decimal32.Precision) + int i; + for (i = 0; i < number.DigitsCount; i++) { - digitsToExtract = Decimal32.Precision; - needToRound = true; + if (i < Decimal32.Precision) + { + // We have more digits than the precision allows + break; + } + + q--; + c *= 10; + c += (uint)(mantissa[i] - '0'); } - else + + if (i < number.DigitsCount) { - digitsToExtract = (uint) number.DigitsCount; - needToRound = false; - } + // We have more digits than the precision allows, we might need to round up + // roundUp = (next digit > 5) + // || ((next digit == 5) && (trailing digits || current digit is odd) + bool roundUp = false; + if (mantissa[i] > '5') + { + roundUp = true; + } + else if (mantissa[i] == '5') + { - uint c = 0; - int q = number.Scale; - uint extractedDigits = 0; - while (true) - { - if ( - c *= 10; - q -= 1; - } + if ((c & 1) == 1) + { + // current digit is odd, round to even regardless of whether or not we have trailing digits + roundUp = true; + } + else + { + // Current digit is even, but there might be trailing digits that cause us to round up anyway + // We might still have some additional digits, in which case they need + // to be considered as part of hasZeroTail. Some examples of this are: + // * 3.0500000000000000000001e-27 + // * 3.05000000000000000000001e-27 + // In these cases, we will have processed 3 and 0, and ended on 5. The + // buffer, however, will still contain a number of trailing zeros and + // a trailing non-zero number. + + bool hasZeroTail = !number.HasNonZeroTail; + i++; + while ((mantissa[i] != 0) && hasZeroTail) + { + hasZeroTail &= (mantissa[i] == '0'); + i++; + } - } + // We should either be at the end of the stream or have a non-zero tail + Debug.Assert((c == 0) || !hasZeroTail); + + if (!hasZeroTail) + { + // If the next digit is 5 with a non-zero tail we must round up + roundUp = true; + } + } - return number.IsNegative ? Decimal32.Negate(result) : result;*/ + } + + if (roundUp) + { + if (++c > Decimal32.MaxSignificand) + { + // We have rounded up to Infinity, return early + return number.IsNegative ? Decimal32.NegativeInfinity : Decimal32.PositiveInfinity; + } + } + } + Debug.Assert(q >= Decimal32.MinQExponent && q <= Decimal32.MaxQExponent); + return new Decimal32(number.IsNegative, (sbyte)q, c); + } } internal enum ParsingStatus // No ParsingStatus.Overflow because these types can represent infinity From e7a86c12e81bd8292484744bedb5474a834a90bd Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Wed, 21 Dec 2022 13:24:46 -0600 Subject: [PATCH 15/39] Fix exception throwing in parsing --- .../src/System/Numerics/IeeeDecimalNumber.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs index 9159d1a8d5c1f5..3ae3b4732f66fe 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs @@ -159,13 +159,13 @@ public override string ToString() private const int Decimal32MinExponent = Decimal32.MinQExponent + Decimal32.Precision; // TODO check this, probably wrong [DoesNotReturn] - internal static void ThrowFormatException(ParsingStatus status, ReadOnlySpan value, TypeCode type = 0) => throw new FormatException(SR.Format(SR.Format_InvalidStringWithValue, value.ToString())); + internal static void ThrowFormatException(ReadOnlySpan value) => throw new FormatException(/*SR.Format(SR.Format_InvalidStringWithValue,*/ value.ToString()/*)*/); internal static Decimal32 ParseDecimal32(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info) { if (!TryParseDecimal32(value, styles, info, out Decimal32 result)) { - ThrowFormatException(ParsingStatus.Failed, value); + ThrowFormatException(value); } return result; From 70e493c894a6ad3fa0054bcbe07dca6b9c2c7293 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Wed, 21 Dec 2022 13:48:27 -0600 Subject: [PATCH 16/39] Add missing parsing elements --- .../src/System/Numerics/Decimal32.cs | 32 +++++++++------ .../src/System/Numerics/IeeeDecimalNumber.cs | 40 +++++++++++-------- .../src/System/ThrowHelper.cs | 6 +++ 3 files changed, 49 insertions(+), 29 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index c26b0c29fa9b29..23d4e666d4334a 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -206,7 +206,7 @@ internal Decimal32(bool s, sbyte q, uint c) // Edge conditions: MinQExponent <= q <= MaxQExponent, 0 <= s <= 9999999 Debug.Assert(q >= MinQExponent && q <= MaxQExponent); Debug.Assert(c <= MaxSignificand); - _value = 0; // TODO + _value = s ? NegativeZeroBits : PositiveZeroBits; // TODO } /// @@ -273,37 +273,37 @@ public static Decimal32 Abs(Decimal32 value) /// public static Decimal32 Parse(ReadOnlySpan s, IFormatProvider? provider) { - // NumberFormatInfo.ValidateParseStyleFloatingPoint(NumberStyles.Number); // TODO, it won't let me call this because it's internal to System. + IeeeDecimalNumber.ValidateParseStyleFloatingPoint(NumberStyles.Number); // TODO I moved this from NumberFormatInfo to IeeeDecimalNumber, is that ok? return IeeeDecimalNumber.ParseDecimal32(s, NumberStyles.Number, NumberFormatInfo.GetInstance(provider)); } /// public static Decimal32 Parse(string s, IFormatProvider? provider) { - // if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); // TODO, it won't let me call this because it's internal to System. + if (s == null) ThrowHelper.ThrowArgumentNullException("s"); return IeeeDecimalNumber.ParseDecimal32(s, NumberStyles.Number, NumberFormatInfo.GetInstance(provider)); } /// public static Decimal32 Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider = null) // TODO what should the default for NumberStyles be? { - // NumberFormatInfo.ValidateParseStyleFloatingPoint(style); // TODO, it won't let me call this because it's internal to System. + IeeeDecimalNumber.ValidateParseStyleFloatingPoint(style); return IeeeDecimalNumber.ParseDecimal32(s, style, NumberFormatInfo.GetInstance(provider)); } /// public static Decimal32 Parse(string s, NumberStyles style, IFormatProvider? provider) { - // NumberFormatInfo.ValidateParseStyleFloatingPoint(style); // TODO, it won't let me call these because they are internal to System. - // if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); + IeeeDecimalNumber.ValidateParseStyleFloatingPoint(style); + if (s == null) ThrowHelper.ThrowArgumentNullException("s"); return IeeeDecimalNumber.ParseDecimal32(s, style, NumberFormatInfo.GetInstance(provider)); } /// public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) { - // NumberFormatInfo.ValidateParseStyleFloatingPoint(NumberStyles.Number); // TODO - return IeeeDecimalNumber.TryParseDecimal32(s, NumberStyles.Number, NumberFormatInfo.GetInstance(provider), out result) == IeeeDecimalNumber.ParsingStatus.OK; + IeeeDecimalNumber.ValidateParseStyleFloatingPoint(NumberStyles.Number); + return IeeeDecimalNumber.TryParseDecimal32(s, NumberStyles.Number, NumberFormatInfo.GetInstance(provider), out result); } /// @@ -312,22 +312,22 @@ public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [Ma /// public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) { - // NumberFormatInfo.ValidateParseStyleFloatingPoint(style); // TODO - return IeeeDecimalNumber.TryParseDecimal32(s, style, NumberFormatInfo.GetInstance(provider), out result) == IeeeDecimalNumber.ParsingStatus.OK; + IeeeDecimalNumber.ValidateParseStyleFloatingPoint(style); + return IeeeDecimalNumber.TryParseDecimal32(s, style, NumberFormatInfo.GetInstance(provider), out result); } /// public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) { - // NumberFormatInfo.ValidateParseStyleFloatingPoint(style); // TODO + IeeeDecimalNumber.ValidateParseStyleFloatingPoint(style); if (s == null) { - result = 0; + result = Zero; return false; } - return IeeeDecimalNumber.TryParseDecimal32(s, style, NumberFormatInfo.GetInstance(provider), out result) == IeeeDecimalNumber.ParsingStatus.OK; + return IeeeDecimalNumber.TryParseDecimal32(s, style, NumberFormatInfo.GetInstance(provider), out result); } public static Decimal32 Pow(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); @@ -409,7 +409,9 @@ public static Decimal32 CreateTruncating(TOther value) static bool INumberBase.TryConvertFromChecked(TOther value, out Decimal32 result) => TryConvertFromChecked(value, out result); [MethodImpl(MethodImplOptions.AggressiveInlining)] +#pragma warning disable IDE0060 // Remove unused parameter private static bool TryConvertFromChecked(TOther value, out Decimal32 result) +#pragma warning restore IDE0060 // Remove unused parameter where TOther : INumberBase { if (typeof(TOther) == typeof(byte)) @@ -492,7 +494,9 @@ private static bool TryConvertFromChecked(TOther value, out Decimal32 re static bool INumberBase.TryConvertFromSaturating(TOther value, out Decimal32 result) => TryConvertFromSaturating(value, out result); [MethodImpl(MethodImplOptions.AggressiveInlining)] +#pragma warning disable IDE0060 // Remove unused parameter private static bool TryConvertFromSaturating(TOther value, out Decimal32 result) +#pragma warning restore IDE0060 // Remove unused parameter where TOther : INumberBase { if (typeof(TOther) == typeof(byte)) @@ -575,7 +579,9 @@ private static bool TryConvertFromSaturating(TOther value, out Decimal32 static bool INumberBase.TryConvertFromTruncating(TOther value, out Decimal32 result) => TryConvertFromTruncating(value, out result); [MethodImpl(MethodImplOptions.AggressiveInlining)] +#pragma warning disable IDE0060 // Remove unused parameter TODO remove this private static bool TryConvertFromTruncating(TOther value, out Decimal32 result) +#pragma warning restore IDE0060 // Remove unused parameter where TOther : INumberBase { if (typeof(TOther) == typeof(byte)) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs index 3ae3b4732f66fe..c0a194d3322bb8 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs @@ -15,22 +15,6 @@ namespace System.Numerics { -/* // Extension of ReadOnlySpan to bring in internal helpers, if needed - internal static partial class MemoryExtensions - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool EqualsOrdinalIgnoreCase(this ReadOnlySpan span, ReadOnlySpan value) - { - if (span.Length != value.Length) - return false; - if (value.Length == 0) // span.Length == value.Length == 0 - return true; - return System.Globalization.Ordinal.EqualsIgnoreCase(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(value), span.Length); - } - - - }*/ - internal static partial class IeeeDecimalNumber { // IeeeDecimalNumberBuffer @@ -689,6 +673,30 @@ internal enum ParsingStatus // No ParsingStatus.Overflow because these types can Failed } + private const NumberStyles InvalidNumberStyles = ~(NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite + | NumberStyles.AllowLeadingSign | NumberStyles.AllowTrailingSign + | NumberStyles.AllowParentheses | NumberStyles.AllowDecimalPoint + | NumberStyles.AllowThousands | NumberStyles.AllowExponent + | NumberStyles.AllowCurrencySymbol | NumberStyles.AllowHexSpecifier); + internal static void ValidateParseStyleFloatingPoint(NumberStyles style) + { + // Check for undefined flags or hex number + if ((style & (InvalidNumberStyles | NumberStyles.AllowHexSpecifier)) != 0) + { + ThrowInvalid(style); + + static void ThrowInvalid(NumberStyles value) + { + if ((value & InvalidNumberStyles) != 0) + { + throw new ArgumentException(SR.Argument_InvalidNumberStyles, nameof(style)); + } + + throw new ArgumentException(SR.Arg_HexStyleNotSupported); + } + } + } + // IeeeDecimalNumber Formatting } } diff --git a/src/libraries/System.Runtime.Numerics/src/System/ThrowHelper.cs b/src/libraries/System.Runtime.Numerics/src/System/ThrowHelper.cs index 3a73f6e2c94671..bbc419073b1b57 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/ThrowHelper.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/ThrowHelper.cs @@ -26,5 +26,11 @@ internal static void ThrowValueArgumentOutOfRange_NeedNonNegNumException() { throw new ArgumentOutOfRangeException("value", SR.ArgumentOutOfRange_NeedNonNegNum); } + + [DoesNotReturn] + internal static void ThrowArgumentNullException(string argumentName) + { + throw new ArgumentNullException(argumentName); + } } } From 2c72ff731cfe64e086cc8b36200010d0510f8ae0 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Wed, 21 Dec 2022 17:17:53 -0600 Subject: [PATCH 17/39] Fill out Decimal32 constructor --- .../src/System/Numerics/Decimal32.cs | 45 +++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index 23d4e666d4334a..91250bd7ca5f46 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -31,15 +31,21 @@ public readonly struct Decimal32 internal const uint CombinationMask = 0x7FF0_0000; internal const int CombinationShift = 20; + internal const int CombinationWidth = 11; + + internal const uint TrailingSignificandMask = 0x000F_FFFF; + internal const int TrailingSignificandWidth = 20; // TODO figure out if these three are useful, I don't think they are internal const uint NaNMask = 0x7C00_0000; internal const uint InfinityMask = 0x7800_0000; - internal const uint TrailingSignificandMask = 0x000F_FFFF; + + // Significands that have this bit set are encoded differently + internal const uint FiniteNumberEncodingCheckMask = 0x0080_0000; // TODO I think these might be useless in Decimal -/* internal const ushort MinCombination = 0x0000; - internal const ushort MaxCombination = 0x07FF;*/ + /* internal const ushort MinCombination = 0x0000; + internal const ushort MaxCombination = 0x07FF;*/ internal const sbyte EMax = 96; internal const sbyte EMin = -95; @@ -98,6 +104,7 @@ public readonly struct Decimal32 // b. Combination field G0 through G10. G0-G4 == 11110 encodes infinity. // c. Trailing significand. // Note: Canonical infinity has everything after G5 set to 0. + private const uint PositiveInfinityBits = 0x7800_0000; private const uint NegativeInfinityBits = SignMask | PositiveInfinityBits; @@ -112,6 +119,7 @@ public readonly struct Decimal32 // b. Combination field G0 through G10. G0-G4 == 11111 encodes NaN. // c. Trailing significand. Can be used to encode a payload, to distinguish different NaNs. // Note: Canonical NaN has G6-G10 as 0 and the encoding of the payload also canonical. + private const uint QNanBits = 0x7C00_0000; // TODO I used a "positive" NaN here, should it be negative? private const uint SNanBits = 0x7E00_0000; @@ -129,6 +137,7 @@ public readonly struct Decimal32 // d. Significand. Section b. indicates an implied prefix of [100]. [100]1_1000_1001_0110_0111_1111 == 9,999,999. // // Encoded value: 9,999,999 x 10^90 + private const uint MaxValueBits = 0x77F8_967F; private const uint MinValueBits = SignMask | MaxValueBits; @@ -194,19 +203,39 @@ internal Decimal32(uint value) _value = value; } - private Decimal32(bool sign, uint combination, uint trailing_sig) => _value = (uint)(((sign ? 1 : 0) << SignShift) + (combination << CombinationShift) + trailing_sig); // TODO do we need this? - // Constructs a Decimal32 representing a value in the form (-1)^s * 10^q * c, where // * s is 0 or 1 // * q is any integer MinQExponent <= q <= MaxQExponent // * c is the significand represented by a digit string of the form // `d0 d1 d2 ... dp-1`, where p is Precision. c is an integer with 0 <= c < 10^p. - internal Decimal32(bool s, sbyte q, uint c) + internal Decimal32(bool sign, sbyte q, uint c) { - // Edge conditions: MinQExponent <= q <= MaxQExponent, 0 <= s <= 9999999 Debug.Assert(q >= MinQExponent && q <= MaxQExponent); + Debug.Assert(q + ExponentBias >= 0); Debug.Assert(c <= MaxSignificand); - _value = s ? NegativeZeroBits : PositiveZeroBits; // TODO + + uint trailing_sig = c & TrailingSignificandMask; + + // Two types of combination encodings for finite numbers + uint combination = 0; + + if ((c & FiniteNumberEncodingCheckMask) == 0) + { + // We are encoding a significand that has the most significand 4 bits set to 0xyz + combination |= (uint)(q + ExponentBias) << 3; + combination |= 0b0111 & (c >> TrailingSignificandWidth); // combination = (biased_exponent, xyz) + + + } + else + { + // We are encoding a significand that has the most significand 4 bits set to 100x + combination |= 0b11 << (CombinationWidth - 2); + combination |= (uint)(q + ExponentBias) << 1; + combination |= 0b0001 & (c >> CombinationShift); // combination = (11, biased_exponent, x) + } + + _value = (uint)(((sign ? 1 : 0) << SignShift) + (combination << CombinationShift) + trailing_sig); } /// From 61611be023cd7f32187acb8ee7a89d6b02719ce9 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Wed, 21 Dec 2022 17:35:38 -0600 Subject: [PATCH 18/39] add Decimal32Tests.cs --- .../System.Runtime.Numerics.sln | 13 +- .../tests/Decimal32Tests.cs | 246 ++++++++++++++++++ .../System.Runtime.Numerics.Tests.csproj | 3 +- 3 files changed, 258 insertions(+), 4 deletions(-) create mode 100644 src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs diff --git a/src/libraries/System.Runtime.Numerics/System.Runtime.Numerics.sln b/src/libraries/System.Runtime.Numerics/System.Runtime.Numerics.sln index 5da865b1d49b3b..c123d8a1a14312 100644 --- a/src/libraries/System.Runtime.Numerics/System.Runtime.Numerics.sln +++ b/src/libraries/System.Runtime.Numerics/System.Runtime.Numerics.sln @@ -1,4 +1,8 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.32818.431 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{A22876CA-76C0-4ABD-8658-C2B3DFDFE537}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryImportGenerator", "..\System.Runtime.InteropServices\gen\LibraryImportGenerator\LibraryImportGenerator.csproj", "{55FC83C5-F34D-4B4B-BEAE-497DD5653BCE}" @@ -14,6 +18,9 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime", "..\System.Runtime\ref\System.Runtime.csproj", "{DB1922E9-EC35-44AC-9677-277B7D00595F}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{A80D3604-A8C8-4B23-B0D3-316E46CFE60A}" + ProjectSection(SolutionItems) = preProject + Decimal32Tests.cs = Decimal32Tests.cs + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{94F2DDDF-A2DA-4F69-9613-A92D50D84A1C}" EndProject @@ -61,12 +68,12 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {A22876CA-76C0-4ABD-8658-C2B3DFDFE537} = {A80D3604-A8C8-4B23-B0D3-316E46CFE60A} - {2C4CBA2D-4C9D-4B83-85A4-2DF75C91B0FC} = {A80D3604-A8C8-4B23-B0D3-316E46CFE60A} {55FC83C5-F34D-4B4B-BEAE-497DD5653BCE} = {94F2DDDF-A2DA-4F69-9613-A92D50D84A1C} {57EC916C-15B4-46BB-AE68-B4CD8BC7076C} = {94F2DDDF-A2DA-4F69-9613-A92D50D84A1C} {C91AC3B4-647B-4D7F-83CA-BE90FFFC8CF3} = {18C5FB7C-2DE7-4BED-BA2B-53776E78E1E5} - {DB1922E9-EC35-44AC-9677-277B7D00595F} = {18C5FB7C-2DE7-4BED-BA2B-53776E78E1E5} {91F8FBEF-C085-4542-BEE4-22449D80734A} = {F6066198-D324-499F-BEB7-55DF39460AB4} + {2C4CBA2D-4C9D-4B83-85A4-2DF75C91B0FC} = {A80D3604-A8C8-4B23-B0D3-316E46CFE60A} + {DB1922E9-EC35-44AC-9677-277B7D00595F} = {18C5FB7C-2DE7-4BED-BA2B-53776E78E1E5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B7C7E4C6-78B9-4AE7-AC8B-4F08EAD0DECB} diff --git a/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs b/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs new file mode 100644 index 00000000000000..30aa02d71d0601 --- /dev/null +++ b/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs @@ -0,0 +1,246 @@ + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Globalization; +using Xunit; + +namespace System.Numerics.Tests +{ + public partial class Decimal32Tests + { + public static IEnumerable Parse_Valid_TestData() + { + NumberStyles defaultStyle = NumberStyles.Float | NumberStyles.AllowThousands; + + NumberFormatInfo emptyFormat = NumberFormatInfo.CurrentInfo; + + var dollarSignCommaSeparatorFormat = new NumberFormatInfo() + { + CurrencySymbol = "$", + CurrencyGroupSeparator = "," + }; + + var decimalSeparatorFormat = new NumberFormatInfo() + { + NumberDecimalSeparator = "." + }; + + NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; + + yield return new object[] { "-123", defaultStyle, null, -123.0f }; + yield return new object[] { "0", defaultStyle, null, 0.0f }; + yield return new object[] { "123", defaultStyle, null, 123.0f }; + yield return new object[] { " 123 ", defaultStyle, null, 123.0f }; + yield return new object[] { (567.89f).ToString(), defaultStyle, null, 567.89f }; + yield return new object[] { (-567.89f).ToString(), defaultStyle, null, -567.89f }; + yield return new object[] { "1E23", defaultStyle, null, 1E23f }; + + yield return new object[] { emptyFormat.NumberDecimalSeparator + "234", defaultStyle, null, 0.234f }; + yield return new object[] { "234" + emptyFormat.NumberDecimalSeparator, defaultStyle, null, 234.0f }; + yield return new object[] { new string('0', 13) + "65504" + emptyFormat.NumberDecimalSeparator, defaultStyle, null, 65504f }; + yield return new object[] { new string('0', 14) + "65504" + emptyFormat.NumberDecimalSeparator, defaultStyle, null, 65504f }; + + // 2^11 + 1. Not exactly representable + yield return new object[] { "2049.0", defaultStyle, invariantFormat, 2048.0f }; + yield return new object[] { "2049.000000000000001", defaultStyle, invariantFormat, 2050.0f }; + yield return new object[] { "2049.0000000000000001", defaultStyle, invariantFormat, 2050.0f }; + yield return new object[] { "2049.00000000000000001", defaultStyle, invariantFormat, 2050.0f }; + yield return new object[] { "5.000000000000000004", defaultStyle, invariantFormat, 5.0f }; + yield return new object[] { "5.0000000000000000004", defaultStyle, invariantFormat, 5.0f }; + yield return new object[] { "5.004", defaultStyle, invariantFormat, 5.004f }; + yield return new object[] { "5.004000000000000000", defaultStyle, invariantFormat, 5.004f }; + yield return new object[] { "5.0040000000000000000", defaultStyle, invariantFormat, 5.004f }; + yield return new object[] { "5.040", defaultStyle, invariantFormat, 5.04f }; + + yield return new object[] { "5004.000000000000000", defaultStyle, invariantFormat, 5004.0f }; + yield return new object[] { "50040.0", defaultStyle, invariantFormat, 50040.0f }; + yield return new object[] { "5004", defaultStyle, invariantFormat, 5004.0f }; + yield return new object[] { "050040", defaultStyle, invariantFormat, 50040.0f }; + yield return new object[] { "0.000000000000000000", defaultStyle, invariantFormat, 0.0f }; + yield return new object[] { "0.005", defaultStyle, invariantFormat, 0.005f }; + yield return new object[] { "0.0400", defaultStyle, invariantFormat, 0.04f }; + yield return new object[] { "1200e0", defaultStyle, invariantFormat, 1200.0f }; + yield return new object[] { "120100e-4", defaultStyle, invariantFormat, 12.01f }; + yield return new object[] { "12010.00e-4", defaultStyle, invariantFormat, 1.201f }; + yield return new object[] { "12000e-4", defaultStyle, invariantFormat, 1.2f }; + yield return new object[] { "1200", defaultStyle, invariantFormat, 1200.0f }; + + yield return new object[] { (123.1f).ToString(), NumberStyles.AllowDecimalPoint, null, 123.1f }; + yield return new object[] { (1000.0f).ToString("N0"), NumberStyles.AllowThousands, null, 1000.0f }; + + yield return new object[] { "123", NumberStyles.Any, emptyFormat, 123.0f }; + yield return new object[] { (123.567f).ToString(), NumberStyles.Any, emptyFormat, 123.567f }; + yield return new object[] { "123", NumberStyles.Float, emptyFormat, 123.0f }; + yield return new object[] { "$1,000", NumberStyles.Currency, dollarSignCommaSeparatorFormat, 1000.0f }; + yield return new object[] { "$1000", NumberStyles.Currency, dollarSignCommaSeparatorFormat, 1000.0f }; + yield return new object[] { "123.123", NumberStyles.Float, decimalSeparatorFormat, 123.123f }; + yield return new object[] { "(123)", NumberStyles.AllowParentheses, decimalSeparatorFormat, -123.0f }; + + yield return new object[] { "NaN", NumberStyles.Any, invariantFormat, float.NaN }; + yield return new object[] { "Infinity", NumberStyles.Any, invariantFormat, float.PositiveInfinity }; + yield return new object[] { "-Infinity", NumberStyles.Any, invariantFormat, float.NegativeInfinity }; + } + + [Theory] + [MemberData(nameof(Parse_Valid_TestData))] + public static void Parse(string value, NumberStyles style, IFormatProvider provider, float expectedFloat) + { + bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo; + Half result; + Half expected = (Half)expectedFloat; + if ((style & ~(NumberStyles.Float | NumberStyles.AllowThousands)) == 0 && style != NumberStyles.None) + { + // Use Parse(string) or Parse(string, IFormatProvider) + if (isDefaultProvider) + { + Assert.True(Half.TryParse(value, out result)); + Assert.True(expected.Equals(result)); + + Assert.Equal(expected, Half.Parse(value)); + } + + Assert.True(expected.Equals(Half.Parse(value, provider: provider))); + } + + // Use Parse(string, NumberStyles, IFormatProvider) + Assert.True(Half.TryParse(value, style, provider, out result)); + Assert.True(expected.Equals(result) || (Half.IsNaN(expected) && Half.IsNaN(result))); + + Assert.True(expected.Equals(Half.Parse(value, style, provider)) || (Half.IsNaN(expected) && Half.IsNaN(result))); + + if (isDefaultProvider) + { + // Use Parse(string, NumberStyles) or Parse(string, NumberStyles, IFormatProvider) + Assert.True(Half.TryParse(value, style, NumberFormatInfo.CurrentInfo, out result)); + Assert.True(expected.Equals(result)); + + Assert.True(expected.Equals(Half.Parse(value, style))); + Assert.True(expected.Equals(Half.Parse(value, style, NumberFormatInfo.CurrentInfo))); + } + } + + public static IEnumerable Parse_Invalid_TestData() + { + NumberStyles defaultStyle = NumberStyles.Float; + + var dollarSignDecimalSeparatorFormat = new NumberFormatInfo(); + dollarSignDecimalSeparatorFormat.CurrencySymbol = "$"; + dollarSignDecimalSeparatorFormat.NumberDecimalSeparator = "."; + + yield return new object[] { null, defaultStyle, null, typeof(ArgumentNullException) }; + yield return new object[] { "", defaultStyle, null, typeof(FormatException) }; + yield return new object[] { " ", defaultStyle, null, typeof(FormatException) }; + yield return new object[] { "Garbage", defaultStyle, null, typeof(FormatException) }; + + yield return new object[] { "ab", defaultStyle, null, typeof(FormatException) }; // Hex value + yield return new object[] { "(123)", defaultStyle, null, typeof(FormatException) }; // Parentheses + yield return new object[] { (100.0f).ToString("C0"), defaultStyle, null, typeof(FormatException) }; // Currency + + yield return new object[] { (123.456f).ToString(), NumberStyles.Integer, null, typeof(FormatException) }; // Decimal + yield return new object[] { " " + (123.456f).ToString(), NumberStyles.None, null, typeof(FormatException) }; // Leading space + yield return new object[] { (123.456f).ToString() + " ", NumberStyles.None, null, typeof(FormatException) }; // Leading space + yield return new object[] { "1E23", NumberStyles.None, null, typeof(FormatException) }; // Exponent + + yield return new object[] { "ab", NumberStyles.None, null, typeof(FormatException) }; // Negative hex value + yield return new object[] { " 123 ", NumberStyles.None, null, typeof(FormatException) }; // Trailing and leading whitespace + } + + [Theory] + [MemberData(nameof(Parse_Invalid_TestData))] + public static void Parse_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType) + { + bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo; + Half result; + if ((style & ~(NumberStyles.Float | NumberStyles.AllowThousands)) == 0 && style != NumberStyles.None && (style & NumberStyles.AllowLeadingWhite) == (style & NumberStyles.AllowTrailingWhite)) + { + // Use Parse(string) or Parse(string, IFormatProvider) + if (isDefaultProvider) + { + Assert.False(Half.TryParse(value, out result)); + Assert.Equal(default(Half), result); + + Assert.Throws(exceptionType, () => Half.Parse(value)); + } + + Assert.Throws(exceptionType, () => Half.Parse(value, provider: provider)); + } + + // Use Parse(string, NumberStyles, IFormatProvider) + Assert.False(Half.TryParse(value, style, provider, out result)); + Assert.Equal(default(Half), result); + + Assert.Throws(exceptionType, () => Half.Parse(value, style, provider)); + + if (isDefaultProvider) + { + // Use Parse(string, NumberStyles) or Parse(string, NumberStyles, IFormatProvider) + Assert.False(Half.TryParse(value, style, NumberFormatInfo.CurrentInfo, out result)); + Assert.Equal(default(Half), result); + + Assert.Throws(exceptionType, () => Half.Parse(value, style)); + Assert.Throws(exceptionType, () => Half.Parse(value, style, NumberFormatInfo.CurrentInfo)); + } + } + + public static IEnumerable Parse_ValidWithOffsetCount_TestData() + { + foreach (object[] inputs in Parse_Valid_TestData()) + { + yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] }; + } + + const NumberStyles DefaultStyle = NumberStyles.Float | NumberStyles.AllowThousands; + + yield return new object[] { "-123", 1, 3, DefaultStyle, null, (float)123 }; + yield return new object[] { "-123", 0, 3, DefaultStyle, null, (float)-12 }; + yield return new object[] { "1E23", 0, 3, DefaultStyle, null, (float)1E2 }; + yield return new object[] { "123", 0, 2, NumberStyles.Float, new NumberFormatInfo(), (float)12 }; + yield return new object[] { "$1,000", 1, 3, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$", CurrencyGroupSeparator = "," }, (float)10 }; + yield return new object[] { "(123)", 1, 3, NumberStyles.AllowParentheses, new NumberFormatInfo() { NumberDecimalSeparator = "." }, (float)123 }; + yield return new object[] { "-Infinity", 1, 8, NumberStyles.Any, NumberFormatInfo.InvariantInfo, float.PositiveInfinity }; + } + + [Theory] + [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))] + public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, float expectedFloat) + { + bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo; + Half result; + Half expected = (Half)expectedFloat; + if ((style & ~(NumberStyles.Float | NumberStyles.AllowThousands)) == 0 && style != NumberStyles.None) + { + // Use Parse(string) or Parse(string, IFormatProvider) + if (isDefaultProvider) + { + Assert.True(Half.TryParse(value.AsSpan(offset, count), out result)); + Assert.Equal(expected, result); + + Assert.Equal(expected, Half.Parse(value.AsSpan(offset, count))); + } + + Assert.Equal(expected, Half.Parse(value.AsSpan(offset, count), provider: provider)); + } + + Assert.True(expected.Equals(Half.Parse(value.AsSpan(offset, count), style, provider)) || (Half.IsNaN(expected) && Half.IsNaN(Half.Parse(value.AsSpan(offset, count), style, provider)))); + + Assert.True(Half.TryParse(value.AsSpan(offset, count), style, provider, out result)); + Assert.True(expected.Equals(result) || (Half.IsNaN(expected) && Half.IsNaN(result))); + } + + [Theory] + [MemberData(nameof(Parse_Invalid_TestData))] + public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType) + { + if (value != null) + { + Assert.Throws(exceptionType, () => float.Parse(value.AsSpan(), style, provider)); + + Assert.False(float.TryParse(value.AsSpan(), style, provider, out float result)); + Assert.Equal(0, result); + } + } + } +} + diff --git a/src/libraries/System.Runtime.Numerics/tests/System.Runtime.Numerics.Tests.csproj b/src/libraries/System.Runtime.Numerics/tests/System.Runtime.Numerics.Tests.csproj index 541786570e7d20..292af0f36a3518 100644 --- a/src/libraries/System.Runtime.Numerics/tests/System.Runtime.Numerics.Tests.csproj +++ b/src/libraries/System.Runtime.Numerics/tests/System.Runtime.Numerics.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent) true @@ -58,6 +58,7 @@ + From 2e5540114fef70fc3a758cab7777eddad21ac9cb Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Wed, 21 Dec 2022 17:38:12 -0600 Subject: [PATCH 19/39] Undo accidental sln change --- .../System.Runtime.Numerics/System.Runtime.Numerics.sln | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/System.Runtime.Numerics.sln b/src/libraries/System.Runtime.Numerics/System.Runtime.Numerics.sln index c123d8a1a14312..8597b7fb2cc642 100644 --- a/src/libraries/System.Runtime.Numerics/System.Runtime.Numerics.sln +++ b/src/libraries/System.Runtime.Numerics/System.Runtime.Numerics.sln @@ -18,9 +18,6 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime", "..\System.Runtime\ref\System.Runtime.csproj", "{DB1922E9-EC35-44AC-9677-277B7D00595F}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{A80D3604-A8C8-4B23-B0D3-316E46CFE60A}" - ProjectSection(SolutionItems) = preProject - Decimal32Tests.cs = Decimal32Tests.cs - EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{94F2DDDF-A2DA-4F69-9613-A92D50D84A1C}" EndProject From b91017616038a7f8a098f1271260df8d53f92659 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Fri, 23 Dec 2022 00:48:47 -0600 Subject: [PATCH 20/39] Finish parsing end to end --- .../src/System/Numerics/Decimal32.cs | 236 +++++++++++++++++- .../src/System/Numerics/IeeeDecimalNumber.cs | 4 - .../tests/Decimal32Tests.cs | 208 ++++++++------- 3 files changed, 335 insertions(+), 113 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index 91250bd7ca5f46..81b1f9069e0832 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -23,6 +23,9 @@ public readonly struct Decimal32 IDecimalFloatingPointIeee754, IMinMaxValue { + + private const NumberStyles DefaultParseStyle = NumberStyles.Float | NumberStyles.AllowThousands; // TODO is this correct? + // Constants for manipulating the private bit-representation // TODO I think adding masks that help us "triage" the type of encoding will be useful. @@ -32,16 +35,22 @@ public readonly struct Decimal32 internal const uint CombinationMask = 0x7FF0_0000; internal const int CombinationShift = 20; internal const int CombinationWidth = 11; + internal const ushort ShiftedCombinationMask = (ushort)(CombinationMask >> CombinationShift); internal const uint TrailingSignificandMask = 0x000F_FFFF; internal const int TrailingSignificandWidth = 20; // TODO figure out if these three are useful, I don't think they are + internal const uint ClassificationMask = 0x7C00_0000; internal const uint NaNMask = 0x7C00_0000; internal const uint InfinityMask = 0x7800_0000; - // Significands that have this bit set are encoded differently - internal const uint FiniteNumberEncodingCheckMask = 0x0080_0000; + + // Significands are encoded based on this bit + internal const uint SignificandEncodingTypeMask = 0x0080_0000; + + // Finite numbers are classified based on these bits + internal const uint FiniteNumberClassifictionMask = 0x6000_0000; // TODO I think these might be useless in Decimal /* internal const ushort MinCombination = 0x0000; @@ -219,7 +228,7 @@ internal Decimal32(bool sign, sbyte q, uint c) // Two types of combination encodings for finite numbers uint combination = 0; - if ((c & FiniteNumberEncodingCheckMask) == 0) + if ((c & SignificandEncodingTypeMask) == 0) { // We are encoding a significand that has the most significand 4 bits set to 0xyz combination |= (uint)(q + ExponentBias) << 3; @@ -238,6 +247,87 @@ internal Decimal32(bool sign, sbyte q, uint c) _value = (uint)(((sign ? 1 : 0) << SignShift) + (combination << CombinationShift) + trailing_sig); } + internal byte BiasedExponent + { + get + { + Debug.Assert(IsFinite(this)); + uint bits = _value; + return ExtractBiasedExponentFromBits(bits); + } + } + + internal sbyte Exponent + { + get + { + Debug.Assert(IsFinite(this)); + return (sbyte)(BiasedExponent - ExponentBias); + } + } + + internal uint Significand + { + get + { + Debug.Assert(IsFinite(this)); + return ExtractSignificandFromBits(_value); + } + } + + internal uint TrailingSignificand + { + get + { + Debug.Assert(IsFinite(this)); // TODO NaN and Inf might want to use this + return _value & TrailingSignificandMask; + } + } + + // returns garbage for infinity and NaN, TODO maybe fix this + internal static byte ExtractBiasedExponentFromBits(uint bits) + { + ushort combination = (ushort)((bits >> CombinationShift) & ShiftedCombinationMask); + + // Two types of encodings for finite numbers + if ((bits & FiniteNumberClassifictionMask) == FiniteNumberClassifictionMask) + { + // G0 and G1 are 11, exponent is stored in G2:G(CombinationWidth - 1) + return (byte)(combination >> 1); + } + else + { + // G0 and G1 are not 11, exponent is stored in G0:G(CombinationWidth - 3) + return (byte)(combination >> 3); + } + } + + internal static uint ExtractSignificandFromBits(uint bits) + { + ushort combination = (ushort)((bits >> CombinationShift) & ShiftedCombinationMask); + + // Two types of encodings for finite numbers + uint significand; + if ((bits & FiniteNumberClassifictionMask) == FiniteNumberClassifictionMask) + { + // G0 and G1 are 11, 4 MSBs of significand are 100x, where x is G(CombinationWidth) + significand = (uint)(0b1000 | (combination & 0b1)); + } + else + { + // G0 and G1 are not 11, 4 MSBs of significand are 0xyz, where G(CombinationWidth - 2):G(CombinationWidth) + significand = (uint)(combination & 0b111); + } + significand <<= TrailingSignificandWidth; + significand += bits & TrailingSignificandMask; + return significand; + } + + private static uint StripSign(Decimal32 value) + { + return value._value & ~SignMask; + } + /// public static Decimal32 Abs(Decimal32 value) { @@ -272,11 +362,17 @@ public static Decimal32 Abs(Decimal32 value) public static bool IsCanonical(Decimal32 value) => throw new NotImplementedException(); public static bool IsComplexNumber(Decimal32 value) => throw new NotImplementedException(); public static bool IsEvenInteger(Decimal32 value) => throw new NotImplementedException(); - public static bool IsFinite(Decimal32 value) => throw new NotImplementedException(); + public static bool IsFinite(Decimal32 value) + { + return StripSign(value) < PositiveInfinityBits; + } public static bool IsImaginaryNumber(Decimal32 value) => throw new NotImplementedException(); public static bool IsInfinity(Decimal32 value) => throw new NotImplementedException(); public static bool IsInteger(Decimal32 value) => throw new NotImplementedException(); - public static bool IsNaN(Decimal32 value) => throw new NotImplementedException(); + public static bool IsNaN(Decimal32 value) + { + return (value._value & ClassificationMask) == NaNMask; + } public static bool IsNegative(Decimal32 value) => throw new NotImplementedException(); public static bool IsNegativeInfinity(Decimal32 value) => throw new NotImplementedException(); public static bool IsNormal(Decimal32 value) => throw new NotImplementedException(); @@ -285,7 +381,10 @@ public static Decimal32 Abs(Decimal32 value) public static bool IsPositiveInfinity(Decimal32 value) => throw new NotImplementedException(); public static bool IsRealNumber(Decimal32 value) => throw new NotImplementedException(); public static bool IsSubnormal(Decimal32 value) => throw new NotImplementedException(); - public static bool IsZero(Decimal32 value) => throw new NotImplementedException(); + public static bool IsZero(Decimal32 value) + { + return value.Significand == 0; + } public static Decimal32 Log(Decimal32 x) => throw new NotImplementedException(); public static Decimal32 Log(Decimal32 x, Decimal32 newBase) => throw new NotImplementedException(); public static Decimal32 Log10(Decimal32 x) => throw new NotImplementedException(); @@ -299,10 +398,21 @@ public static Decimal32 Abs(Decimal32 value) // Parsing (INumberBase, IParsable, ISpanParsable) // + /// + /// Parses a from a in the default parse style. + /// + /// The input to be parsed. + /// The equivalent value representing the input string. If the input exceeds Decimal32's range, a or is returned. + public static Decimal32 Parse(string s) + { + if (s == null) ThrowHelper.ThrowArgumentNullException("s"); + return IeeeDecimalNumber.ParseDecimal32(s, DefaultParseStyle, NumberFormatInfo.CurrentInfo); + } + /// public static Decimal32 Parse(ReadOnlySpan s, IFormatProvider? provider) { - IeeeDecimalNumber.ValidateParseStyleFloatingPoint(NumberStyles.Number); // TODO I moved this from NumberFormatInfo to IeeeDecimalNumber, is that ok? + IeeeDecimalNumber.ValidateParseStyleFloatingPoint(NumberStyles.Number); // TODO I copied this from NumberFormatInfo to IeeeDecimalNumber, is that ok? return IeeeDecimalNumber.ParseDecimal32(s, NumberStyles.Number, NumberFormatInfo.GetInstance(provider)); } @@ -314,7 +424,7 @@ public static Decimal32 Parse(string s, IFormatProvider? provider) } /// - public static Decimal32 Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider = null) // TODO what should the default for NumberStyles be? + public static Decimal32 Parse(ReadOnlySpan s, NumberStyles style = DefaultParseStyle, IFormatProvider? provider = null) { IeeeDecimalNumber.ValidateParseStyleFloatingPoint(style); return IeeeDecimalNumber.ParseDecimal32(s, style, NumberFormatInfo.GetInstance(provider)); @@ -328,6 +438,33 @@ public static Decimal32 Parse(string s, NumberStyles style, IFormatProvider? pro return IeeeDecimalNumber.ParseDecimal32(s, style, NumberFormatInfo.GetInstance(provider)); } + /// + /// Tries to parse a from a in the default parse style. + /// + /// The input to be parsed. + /// The equivalent value representing the input string if the parse was successful. If the input exceeds Decimal32's range, a or is returned. If the parse was unsuccessful, a default value is returned. + /// if the parse was successful, otherwise. + public static bool TryParse([NotNullWhen(true)] string? s, out Decimal32 result) + { + if (s == null) + { + result = default; + return false; + } + return TryParse(s, DefaultParseStyle, provider: null, out result); + } + + /// + /// Tries to parse a from a in the default parse style. + /// + /// The input to be parsed. + /// The equivalent value representing the input string if the parse was successful. If the input exceeds Decimal32's range, a or is returned. If the parse was unsuccessful, a default value is returned. + /// if the parse was successful, otherwise. + public static bool TryParse(ReadOnlySpan s, out Decimal32 result) + { + return TryParse(s, DefaultParseStyle, provider: null, out result); + } + /// public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) { @@ -360,11 +497,19 @@ public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, I } public static Decimal32 Pow(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); - public static Decimal32 Quantize(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + public static Decimal32 Quantize(Decimal32 x, Decimal32 y) + { + throw new NotImplementedException(); + } public static Decimal32 Quantum(Decimal32 x) => throw new NotImplementedException(); public static Decimal32 RootN(Decimal32 x, int n) => throw new NotImplementedException(); public static Decimal32 Round(Decimal32 x, int digits, MidpointRounding mode) => throw new NotImplementedException(); - public static bool SameQuantum(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + public static bool SameQuantum(Decimal32 x, Decimal32 y) + { + return x.Exponent == y.Exponent + || (IsInfinity(x) && IsInfinity(y)) + || (IsNaN(x) && IsNaN(y)); + } public static Decimal32 ScaleB(Decimal32 x, int n) => throw new NotImplementedException(); public static Decimal32 Sin(Decimal32 x) => throw new NotImplementedException(); public static (Decimal32 Sin, Decimal32 Cos) SinCos(Decimal32 x) => throw new NotImplementedException(); @@ -935,7 +1080,11 @@ static bool INumberBase.TryConvertToTruncating(Decimal32 valu public int CompareTo(Decimal32 other) => throw new NotImplementedException(); public int CompareTo(object? obj) => throw new NotImplementedException(); - public bool Equals(Decimal32 other) => throw new NotImplementedException(); + public bool Equals(Decimal32 other) + { + return this == other + || (IsNaN(this) && IsNaN(other)); + } public int GetExponentByteCount() => throw new NotImplementedException(); public int GetExponentShortestBitLength() => throw new NotImplementedException(); public int GetSignificandBitLength() => throw new NotImplementedException(); @@ -956,7 +1105,70 @@ static bool INumberBase.TryConvertToTruncating(Decimal32 valu public static Decimal32 operator *(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); public static Decimal32 operator /(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); public static Decimal32 operator %(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); - public static bool operator ==(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + + // Fast access for 10^n where n is 0:(Precision - 1) + private static readonly uint[] s_powers10 = new uint[] { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000 + }; + + public static bool operator ==(Decimal32 left, Decimal32 right) // TODO we can probably do this faster + { + if (IsNaN(left) || IsNaN(right)) + { + // IEEE defines that NaN is not equal to anything, including itself. + return false; + } + + if (IsZero(left) && IsZero(right)) + { + // IEEE defines that positive and negative zero are equivalent. + return true; + } + // IEEE defines that two values of the same cohort are numerically equivalent, + + uint leftSignificand = left.Significand; + uint rightSignificand = right.Significand; + sbyte leftQ = left.Exponent; + sbyte rightQ = right.Exponent; + int diffQ = leftQ - rightQ; + + bool sameNumericalValue = false; + if (int.Abs(diffQ) < Precision) // If diffQ is >= Precision, the non-zero finite values have exponents too far apart for them to possibly be equal + { + try + { + if (diffQ < 0) + { + // leftQ is smaller than rightQ, scale leftSignificand + leftSignificand = checked(leftSignificand * s_powers10[int.Abs(diffQ)]); + } + else + { + // rightQ is smaller than (or equal to) leftQ, scale rightSignificand + rightSignificand = checked(rightSignificand * s_powers10[diffQ]); + } + } + catch + { + // multiplication overflowed, return false + return false; + } + + if (leftSignificand == rightSignificand) + { + sameNumericalValue = true; + } + } + + bool sameSign = IsPositive(left) == IsPositive(right); + return sameNumericalValue && sameSign; + } public static bool operator !=(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); public static bool operator <(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); public static bool operator >(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs index c0a194d3322bb8..99664e6f2ec80a 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs @@ -52,7 +52,6 @@ public IeeeDecimalNumberBuffer(Span digits) CheckConsistency(); } -#pragma warning disable CA1822 [Conditional("DEBUG")] public void CheckConsistency() { @@ -76,15 +75,12 @@ public void CheckConsistency() Debug.Assert(numDigits < Digits.Length, "Null terminator not found in IeeeDecimalNumber"); #endif // DEBUG } -#pragma warning restore CA1822 -#pragma warning disable CA1822 // TODO I don't know why this is required, it isn't for Number.NumberBuffer.cs public byte* GetDigitsPointer() // TODO this is complaining that the method could be static, but it is wrong { // This is safe to do since we are a ref struct return (byte*)(Unsafe.AsPointer(ref Digits[0])); } -#pragma warning restore CA1822 // // Code coverage note: This only exists so that Number displays nicely in the VS watch window. So yes, I know it works. diff --git a/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs b/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs index 30aa02d71d0601..ca95e7e6f1e099 100644 --- a/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs +++ b/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Globalization; +using Newtonsoft.Json.Linq; using Xunit; namespace System.Numerics.Tests @@ -29,95 +30,109 @@ public static IEnumerable Parse_Valid_TestData() NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; - yield return new object[] { "-123", defaultStyle, null, -123.0f }; - yield return new object[] { "0", defaultStyle, null, 0.0f }; - yield return new object[] { "123", defaultStyle, null, 123.0f }; - yield return new object[] { " 123 ", defaultStyle, null, 123.0f }; - yield return new object[] { (567.89f).ToString(), defaultStyle, null, 567.89f }; - yield return new object[] { (-567.89f).ToString(), defaultStyle, null, -567.89f }; - yield return new object[] { "1E23", defaultStyle, null, 1E23f }; - - yield return new object[] { emptyFormat.NumberDecimalSeparator + "234", defaultStyle, null, 0.234f }; - yield return new object[] { "234" + emptyFormat.NumberDecimalSeparator, defaultStyle, null, 234.0f }; - yield return new object[] { new string('0', 13) + "65504" + emptyFormat.NumberDecimalSeparator, defaultStyle, null, 65504f }; - yield return new object[] { new string('0', 14) + "65504" + emptyFormat.NumberDecimalSeparator, defaultStyle, null, 65504f }; - - // 2^11 + 1. Not exactly representable - yield return new object[] { "2049.0", defaultStyle, invariantFormat, 2048.0f }; - yield return new object[] { "2049.000000000000001", defaultStyle, invariantFormat, 2050.0f }; - yield return new object[] { "2049.0000000000000001", defaultStyle, invariantFormat, 2050.0f }; - yield return new object[] { "2049.00000000000000001", defaultStyle, invariantFormat, 2050.0f }; - yield return new object[] { "5.000000000000000004", defaultStyle, invariantFormat, 5.0f }; - yield return new object[] { "5.0000000000000000004", defaultStyle, invariantFormat, 5.0f }; - yield return new object[] { "5.004", defaultStyle, invariantFormat, 5.004f }; - yield return new object[] { "5.004000000000000000", defaultStyle, invariantFormat, 5.004f }; - yield return new object[] { "5.0040000000000000000", defaultStyle, invariantFormat, 5.004f }; - yield return new object[] { "5.040", defaultStyle, invariantFormat, 5.04f }; - - yield return new object[] { "5004.000000000000000", defaultStyle, invariantFormat, 5004.0f }; - yield return new object[] { "50040.0", defaultStyle, invariantFormat, 50040.0f }; - yield return new object[] { "5004", defaultStyle, invariantFormat, 5004.0f }; - yield return new object[] { "050040", defaultStyle, invariantFormat, 50040.0f }; - yield return new object[] { "0.000000000000000000", defaultStyle, invariantFormat, 0.0f }; - yield return new object[] { "0.005", defaultStyle, invariantFormat, 0.005f }; - yield return new object[] { "0.0400", defaultStyle, invariantFormat, 0.04f }; - yield return new object[] { "1200e0", defaultStyle, invariantFormat, 1200.0f }; - yield return new object[] { "120100e-4", defaultStyle, invariantFormat, 12.01f }; - yield return new object[] { "12010.00e-4", defaultStyle, invariantFormat, 1.201f }; - yield return new object[] { "12000e-4", defaultStyle, invariantFormat, 1.2f }; - yield return new object[] { "1200", defaultStyle, invariantFormat, 1200.0f }; - - yield return new object[] { (123.1f).ToString(), NumberStyles.AllowDecimalPoint, null, 123.1f }; - yield return new object[] { (1000.0f).ToString("N0"), NumberStyles.AllowThousands, null, 1000.0f }; - - yield return new object[] { "123", NumberStyles.Any, emptyFormat, 123.0f }; - yield return new object[] { (123.567f).ToString(), NumberStyles.Any, emptyFormat, 123.567f }; - yield return new object[] { "123", NumberStyles.Float, emptyFormat, 123.0f }; - yield return new object[] { "$1,000", NumberStyles.Currency, dollarSignCommaSeparatorFormat, 1000.0f }; - yield return new object[] { "$1000", NumberStyles.Currency, dollarSignCommaSeparatorFormat, 1000.0f }; - yield return new object[] { "123.123", NumberStyles.Float, decimalSeparatorFormat, 123.123f }; - yield return new object[] { "(123)", NumberStyles.AllowParentheses, decimalSeparatorFormat, -123.0f }; - - yield return new object[] { "NaN", NumberStyles.Any, invariantFormat, float.NaN }; - yield return new object[] { "Infinity", NumberStyles.Any, invariantFormat, float.PositiveInfinity }; - yield return new object[] { "-Infinity", NumberStyles.Any, invariantFormat, float.NegativeInfinity }; + // Decimal32(sign, q, c) = -1^sign * 10^q * c + yield return new object[] { "-123", defaultStyle, null, new Decimal32(true, 0, 123) }; + yield return new object[] { "0", defaultStyle, null, Decimal32.Zero }; // TODO what kind of zero do we want to store here? + yield return new object[] { "123", defaultStyle, null, new Decimal32(false, 0, 123) }; + yield return new object[] { " 123 ", defaultStyle, null, new Decimal32(false, 0, 123) }; + yield return new object[] { "567.89", defaultStyle, null, new Decimal32(false, -2, 56789) }; + yield return new object[] { "-567.89", defaultStyle, null, new Decimal32(true, 0, 123) }; + yield return new object[] { "1E23", defaultStyle, null, new Decimal32(false, 23, 1) }; + + yield return new object[] { emptyFormat.NumberDecimalSeparator + "234", defaultStyle, null, new Decimal32(false, -3, 234) }; + yield return new object[] { "234" + emptyFormat.NumberDecimalSeparator, defaultStyle, null, new Decimal32(false, 0, 234) }; + yield return new object[] { new string('0', 72) + "3" + new string('0', 38) + emptyFormat.NumberDecimalSeparator, defaultStyle, null, new Decimal32(false, 38, 3) }; // could be wrong + yield return new object[] { new string('0', 73) + "3" + new string('0', 38) + emptyFormat.NumberDecimalSeparator, defaultStyle, null, new Decimal32(false, 38, 3) }; // could be wrong + + // 10^7 + 5. Not exactly representable + yield return new object[] { "10000005.0", defaultStyle, invariantFormat, new Decimal32(false, 1, 1000000) }; + yield return new object[] { "10000005.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", defaultStyle, invariantFormat, new Decimal32(false, 1, 1000001) }; + yield return new object[] { "10000005.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", defaultStyle, invariantFormat, new Decimal32(false, 1, 1000001) }; + yield return new object[] { "10000005.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", defaultStyle, invariantFormat, new Decimal32(false, 1, 1000001) }; + yield return new object[] { "5.005", defaultStyle, invariantFormat, new Decimal32(false, -3, 5005) }; + yield return new object[] { "5.050", defaultStyle, invariantFormat, new Decimal32(false, -3, 5050) }; + yield return new object[] { "5.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005", defaultStyle, invariantFormat, new Decimal32(false, -6, 5000000) }; + yield return new object[] { "5.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005", defaultStyle, invariantFormat, new Decimal32(false, -6, 5000000) }; + yield return new object[] { "5.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005", defaultStyle, invariantFormat, new Decimal32(false, -6, 5000000) }; + yield return new object[] { "5.005000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, new Decimal32(false, -6, 5050000) }; + yield return new object[] { "5.0050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, new Decimal32(false, -6, 5050000) }; + yield return new object[] { "5.0050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, new Decimal32(false, -6, 5005000) }; + + yield return new object[] { "5005.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, new Decimal32(false, -3, 5005000) }; + yield return new object[] { "50050.0", defaultStyle, invariantFormat, new Decimal32(false, -1, 500500) }; + yield return new object[] { "5005", defaultStyle, invariantFormat, new Decimal32(false, 0, 5005) }; + yield return new object[] { "050050", defaultStyle, invariantFormat, new Decimal32(false, 0, 50050) }; + yield return new object[] { "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, Decimal32.Zero }; + yield return new object[] { "0.005", defaultStyle, invariantFormat, new Decimal32(false, -3, 5) }; + yield return new object[] { "0.0500", defaultStyle, invariantFormat, new Decimal32(false, -4, 500) }; + yield return new object[] { "6250000000000000000000000000000000e-12", defaultStyle, invariantFormat, new Decimal32(false, 15, 6250000) }; + yield return new object[] { "6250000e0", defaultStyle, invariantFormat, new Decimal32(false, 0, 6250000) }; + yield return new object[] { "6250100e-5", defaultStyle, invariantFormat, new Decimal32(false, -5, 6250100) }; + yield return new object[] { "625010.00e-4", defaultStyle, invariantFormat, new Decimal32(false, -5, 6250100) }; + yield return new object[] { "62500e-4", defaultStyle, invariantFormat, new Decimal32(false, -4, 62500) }; + yield return new object[] { "62500", defaultStyle, invariantFormat, new Decimal32(false, 0, 62500) }; + + yield return new object[] { "123.1", NumberStyles.AllowDecimalPoint, null, new Decimal32(false, -1, 1231) }; + yield return new object[] { "1000.0", NumberStyles.AllowThousands, null, new Decimal32(false, -1, 10000) }; + + yield return new object[] { "123", NumberStyles.Any, emptyFormat, new Decimal32(false, 0, 123) }; + yield return new object[] { "123.567", NumberStyles.Any, emptyFormat, new Decimal32(false, -3, 123567) }; + yield return new object[] { "123", NumberStyles.Float, emptyFormat, new Decimal32(false, 0, 123) }; + yield return new object[] { "$1,000", NumberStyles.Currency, dollarSignCommaSeparatorFormat, new Decimal32(false, 0, 1000) }; + yield return new object[] { "$1000", NumberStyles.Currency, dollarSignCommaSeparatorFormat, new Decimal32(false, 0, 1000) }; + yield return new object[] { "123.123", NumberStyles.Float, decimalSeparatorFormat, new Decimal32(false, -3, 123123) }; + yield return new object[] { "(123)", NumberStyles.AllowParentheses, decimalSeparatorFormat, new Decimal32(false, 0, 123) }; + + yield return new object[] { "NaN", NumberStyles.Any, invariantFormat, Decimal32.NaN }; + yield return new object[] { "Infinity", NumberStyles.Any, invariantFormat, Decimal32.PositiveInfinity }; + yield return new object[] { "-Infinity", NumberStyles.Any, invariantFormat, Decimal32.NegativeInfinity }; } - [Theory] + private static void AssertEqualAndSameQuantum(Decimal32 expected, Decimal32 result) + { + Assert.Equal(expected, result); + Assert.True(Decimal32.SameQuantum(expected, result)); + } + + private static void AssertEqualAndSameQuantumOrBothNan(Decimal32 expected, Decimal32 result) + { + Assert.True((expected.Equals(result) && Decimal32.SameQuantum(expected, result)) || (Decimal32.IsNaN(expected) && Decimal32.IsNaN(result))); + } + + [Theory] [MemberData(nameof(Parse_Valid_TestData))] - public static void Parse(string value, NumberStyles style, IFormatProvider provider, float expectedFloat) + public static void Parse(string value, NumberStyles style, IFormatProvider provider, Decimal32 expected) { bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo; - Half result; - Half expected = (Half)expectedFloat; + Decimal32 result; if ((style & ~(NumberStyles.Float | NumberStyles.AllowThousands)) == 0 && style != NumberStyles.None) { // Use Parse(string) or Parse(string, IFormatProvider) if (isDefaultProvider) { - Assert.True(Half.TryParse(value, out result)); - Assert.True(expected.Equals(result)); + Assert.True(Decimal32.TryParse(value, out result)); + AssertEqualAndSameQuantum(expected, result); - Assert.Equal(expected, Half.Parse(value)); + AssertEqualAndSameQuantum(expected, Decimal32.Parse(value)); } - Assert.True(expected.Equals(Half.Parse(value, provider: provider))); + AssertEqualAndSameQuantum(expected, Decimal32.Parse(value, provider: provider)); } // Use Parse(string, NumberStyles, IFormatProvider) - Assert.True(Half.TryParse(value, style, provider, out result)); - Assert.True(expected.Equals(result) || (Half.IsNaN(expected) && Half.IsNaN(result))); + Assert.True(Decimal32.TryParse(value, style, provider, out result)); - Assert.True(expected.Equals(Half.Parse(value, style, provider)) || (Half.IsNaN(expected) && Half.IsNaN(result))); + AssertEqualAndSameQuantumOrBothNan(expected, result); + AssertEqualAndSameQuantumOrBothNan(expected, Decimal32.Parse(value, style, provider)); if (isDefaultProvider) { // Use Parse(string, NumberStyles) or Parse(string, NumberStyles, IFormatProvider) - Assert.True(Half.TryParse(value, style, NumberFormatInfo.CurrentInfo, out result)); - Assert.True(expected.Equals(result)); + Assert.True(Decimal32.TryParse(value, style, NumberFormatInfo.CurrentInfo, out result)); + AssertEqualAndSameQuantum(expected, result); - Assert.True(expected.Equals(Half.Parse(value, style))); - Assert.True(expected.Equals(Half.Parse(value, style, NumberFormatInfo.CurrentInfo))); + AssertEqualAndSameQuantum(expected, Decimal32.Parse(value)); + AssertEqualAndSameQuantum(expected, Decimal32.Parse(value, style, NumberFormatInfo.CurrentInfo)); } } @@ -152,35 +167,35 @@ public static IEnumerable Parse_Invalid_TestData() public static void Parse_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType) { bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo; - Half result; + Decimal32 result; if ((style & ~(NumberStyles.Float | NumberStyles.AllowThousands)) == 0 && style != NumberStyles.None && (style & NumberStyles.AllowLeadingWhite) == (style & NumberStyles.AllowTrailingWhite)) { // Use Parse(string) or Parse(string, IFormatProvider) if (isDefaultProvider) { - Assert.False(Half.TryParse(value, out result)); - Assert.Equal(default(Half), result); + Assert.False(Decimal32.TryParse(value, out result)); + Assert.Equal(default(Decimal32), result); - Assert.Throws(exceptionType, () => Half.Parse(value)); + Assert.Throws(exceptionType, () => Decimal32.Parse(value)); } - Assert.Throws(exceptionType, () => Half.Parse(value, provider: provider)); + Assert.Throws(exceptionType, () => Decimal32.Parse(value, provider: provider)); } // Use Parse(string, NumberStyles, IFormatProvider) - Assert.False(Half.TryParse(value, style, provider, out result)); - Assert.Equal(default(Half), result); + Assert.False(Decimal32.TryParse(value, style, provider, out result)); + Assert.Equal(default(Decimal32), result); - Assert.Throws(exceptionType, () => Half.Parse(value, style, provider)); + Assert.Throws(exceptionType, () => Decimal32.Parse(value, style, provider)); if (isDefaultProvider) { // Use Parse(string, NumberStyles) or Parse(string, NumberStyles, IFormatProvider) - Assert.False(Half.TryParse(value, style, NumberFormatInfo.CurrentInfo, out result)); - Assert.Equal(default(Half), result); + Assert.False(Decimal32.TryParse(value, style, NumberFormatInfo.CurrentInfo, out result)); + Assert.Equal(default(Decimal32), result); - Assert.Throws(exceptionType, () => Half.Parse(value, style)); - Assert.Throws(exceptionType, () => Half.Parse(value, style, NumberFormatInfo.CurrentInfo)); + Assert.Throws(exceptionType, () => Decimal32.Parse(value, style)); + Assert.Throws(exceptionType, () => Decimal32.Parse(value, style, NumberFormatInfo.CurrentInfo)); } } @@ -193,40 +208,39 @@ public static IEnumerable Parse_ValidWithOffsetCount_TestData() const NumberStyles DefaultStyle = NumberStyles.Float | NumberStyles.AllowThousands; - yield return new object[] { "-123", 1, 3, DefaultStyle, null, (float)123 }; - yield return new object[] { "-123", 0, 3, DefaultStyle, null, (float)-12 }; - yield return new object[] { "1E23", 0, 3, DefaultStyle, null, (float)1E2 }; - yield return new object[] { "123", 0, 2, NumberStyles.Float, new NumberFormatInfo(), (float)12 }; - yield return new object[] { "$1,000", 1, 3, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$", CurrencyGroupSeparator = "," }, (float)10 }; - yield return new object[] { "(123)", 1, 3, NumberStyles.AllowParentheses, new NumberFormatInfo() { NumberDecimalSeparator = "." }, (float)123 }; - yield return new object[] { "-Infinity", 1, 8, NumberStyles.Any, NumberFormatInfo.InvariantInfo, float.PositiveInfinity }; + yield return new object[] { "-123", 1, 3, DefaultStyle, null, new Decimal32(false, 0, 123) }; + yield return new object[] { "-123", 0, 3, DefaultStyle, null, new Decimal32(true, 0, 12) }; + yield return new object[] { "1E23", 0, 3, DefaultStyle, null, new Decimal32(false, 2, 1) }; + yield return new object[] { "123", 0, 2, NumberStyles.Float, new NumberFormatInfo(), new Decimal32(false, 0, 12) }; + yield return new object[] { "$1,000", 1, 3, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$", CurrencyGroupSeparator = "," }, new Decimal32(false, 0, 10) }; + yield return new object[] { "(123)", 1, 3, NumberStyles.AllowParentheses, new NumberFormatInfo() { NumberDecimalSeparator = "." }, new Decimal32(false, 0, 123) }; + yield return new object[] { "-Infinity", 1, 8, NumberStyles.Any, NumberFormatInfo.InvariantInfo, Decimal32.PositiveInfinity }; } [Theory] [MemberData(nameof(Parse_ValidWithOffsetCount_TestData))] - public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, float expectedFloat) + public static void Parse_Span_Valid(string value, int offset, int count, NumberStyles style, IFormatProvider provider, Decimal32 expected) { bool isDefaultProvider = provider == null || provider == NumberFormatInfo.CurrentInfo; - Half result; - Half expected = (Half)expectedFloat; + Decimal32 result; if ((style & ~(NumberStyles.Float | NumberStyles.AllowThousands)) == 0 && style != NumberStyles.None) { // Use Parse(string) or Parse(string, IFormatProvider) if (isDefaultProvider) { - Assert.True(Half.TryParse(value.AsSpan(offset, count), out result)); - Assert.Equal(expected, result); + Assert.True(Decimal32.TryParse(value.AsSpan(offset, count), out result)); + AssertEqualAndSameQuantum(expected, result); - Assert.Equal(expected, Half.Parse(value.AsSpan(offset, count))); + AssertEqualAndSameQuantum(expected, Decimal32.Parse(value.AsSpan(offset, count))); } - Assert.Equal(expected, Half.Parse(value.AsSpan(offset, count), provider: provider)); + AssertEqualAndSameQuantum(expected, Decimal32.Parse(value.AsSpan(offset, count), provider: provider)); } - Assert.True(expected.Equals(Half.Parse(value.AsSpan(offset, count), style, provider)) || (Half.IsNaN(expected) && Half.IsNaN(Half.Parse(value.AsSpan(offset, count), style, provider)))); + AssertEqualAndSameQuantumOrBothNan(expected, Decimal32.Parse(value.AsSpan(offset, count), style, provider)); - Assert.True(Half.TryParse(value.AsSpan(offset, count), style, provider, out result)); - Assert.True(expected.Equals(result) || (Half.IsNaN(expected) && Half.IsNaN(result))); + Assert.True(Decimal32.TryParse(value.AsSpan(offset, count), style, provider, out result)); + AssertEqualAndSameQuantumOrBothNan(expected, result); } [Theory] @@ -238,7 +252,7 @@ public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatP Assert.Throws(exceptionType, () => float.Parse(value.AsSpan(), style, provider)); Assert.False(float.TryParse(value.AsSpan(), style, provider, out float result)); - Assert.Equal(0, result); + Assert.Equal(0, result); // TODO is this right? } } } From 8e03769e06e7c6f0d81e09301027c1adeb8ef861 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Tue, 27 Dec 2022 14:21:46 -0600 Subject: [PATCH 21/39] 30 out of 48 parse tests passing --- .../src/System/Numerics/Decimal32.cs | 66 +++++++++++++++---- .../src/System/Numerics/IeeeDecimalNumber.cs | 2 +- .../tests/Decimal32Tests.cs | 9 ++- 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index 81b1f9069e0832..0fe5dc93581b4f 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -251,7 +251,6 @@ internal byte BiasedExponent { get { - Debug.Assert(IsFinite(this)); uint bits = _value; return ExtractBiasedExponentFromBits(bits); } @@ -261,7 +260,6 @@ internal sbyte Exponent { get { - Debug.Assert(IsFinite(this)); return (sbyte)(BiasedExponent - ExponentBias); } } @@ -270,7 +268,6 @@ internal uint Significand { get { - Debug.Assert(IsFinite(this)); return ExtractSignificandFromBits(_value); } } @@ -302,6 +299,7 @@ internal static byte ExtractBiasedExponentFromBits(uint bits) } } + // TODO this returns garbage for Inf and NaN internal static uint ExtractSignificandFromBits(uint bits) { ushort combination = (ushort)((bits >> CombinationShift) & ShiftedCombinationMask); @@ -367,18 +365,33 @@ public static bool IsFinite(Decimal32 value) return StripSign(value) < PositiveInfinityBits; } public static bool IsImaginaryNumber(Decimal32 value) => throw new NotImplementedException(); - public static bool IsInfinity(Decimal32 value) => throw new NotImplementedException(); + public static bool IsInfinity(Decimal32 value) + { + return (value._value & ClassificationMask) == InfinityMask; + } public static bool IsInteger(Decimal32 value) => throw new NotImplementedException(); public static bool IsNaN(Decimal32 value) { return (value._value & ClassificationMask) == NaNMask; } - public static bool IsNegative(Decimal32 value) => throw new NotImplementedException(); - public static bool IsNegativeInfinity(Decimal32 value) => throw new NotImplementedException(); + public static bool IsNegative(Decimal32 value) + { + return (int)(value._value) < 0; + } + public static bool IsNegativeInfinity(Decimal32 value) + { + return IsInfinity(value) && IsNegative(value); + } public static bool IsNormal(Decimal32 value) => throw new NotImplementedException(); public static bool IsOddInteger(Decimal32 value) => throw new NotImplementedException(); - public static bool IsPositive(Decimal32 value) => throw new NotImplementedException(); - public static bool IsPositiveInfinity(Decimal32 value) => throw new NotImplementedException(); + public static bool IsPositive(Decimal32 value) + { + return (int)(value._value) >= 0; + } + public static bool IsPositiveInfinity(Decimal32 value) + { + return IsInfinity(value) && IsPositive(value); + } public static bool IsRealNumber(Decimal32 value) => throw new NotImplementedException(); public static bool IsSubnormal(Decimal32 value) => throw new NotImplementedException(); public static bool IsZero(Decimal32 value) @@ -1130,7 +1143,22 @@ public bool Equals(Decimal32 other) // IEEE defines that positive and negative zero are equivalent. return true; } - // IEEE defines that two values of the same cohort are numerically equivalent, + + bool sameSign = IsPositive(left) == IsPositive(right); + + if (IsInfinity(left) || IsInfinity(right)) + { + if (IsInfinity(left) && IsInfinity(right) && sameSign) + { + return true; + } + else + { + return false; + } + } + + // IEEE defines that two values of the same cohort are numerically equivalent uint leftSignificand = left.Significand; uint rightSignificand = right.Significand; @@ -1166,7 +1194,6 @@ public bool Equals(Decimal32 other) } } - bool sameSign = IsPositive(left) == IsPositive(right); return sameNumericalValue && sameSign; } public static bool operator !=(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); @@ -1185,7 +1212,24 @@ public override int GetHashCode() throw new NotImplementedException(); } - public string ToString(string? format, IFormatProvider? formatProvider) => throw new NotImplementedException(); + public string ToString(string? format, IFormatProvider? formatProvider) + { + // Temporary Formatting for debugging + if (IsNaN(this)) + { + return "NaN"; + } + else if (IsPositiveInfinity(this)) + { + return "Infinity"; + } + else if (IsNegativeInfinity(this)) + { + return "-Infinity"; + } + + return (IsPositive(this) ? "" : "-") + Significand.ToString() + "E" + Exponent.ToString(); + } // IEEE 754 specifies NaNs to be propagated internal static Decimal32 Negate(Decimal32 value) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs index 99664e6f2ec80a..63de09004192aa 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs @@ -587,7 +587,7 @@ internal static unsafe Decimal32 NumberToDecimal32(ref IeeeDecimalNumberBuffer n int i; for (i = 0; i < number.DigitsCount; i++) { - if (i < Decimal32.Precision) + if (i >= Decimal32.Precision) { // We have more digits than the precision allows break; diff --git a/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs b/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs index ca95e7e6f1e099..434f82bf339a68 100644 --- a/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs +++ b/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs @@ -36,7 +36,7 @@ public static IEnumerable Parse_Valid_TestData() yield return new object[] { "123", defaultStyle, null, new Decimal32(false, 0, 123) }; yield return new object[] { " 123 ", defaultStyle, null, new Decimal32(false, 0, 123) }; yield return new object[] { "567.89", defaultStyle, null, new Decimal32(false, -2, 56789) }; - yield return new object[] { "-567.89", defaultStyle, null, new Decimal32(true, 0, 123) }; + yield return new object[] { "-567.89", defaultStyle, null, new Decimal32(true, -2, 56789) }; yield return new object[] { "1E23", defaultStyle, null, new Decimal32(false, 23, 1) }; yield return new object[] { emptyFormat.NumberDecimalSeparator + "234", defaultStyle, null, new Decimal32(false, -3, 234) }; @@ -96,10 +96,13 @@ private static void AssertEqualAndSameQuantum(Decimal32 expected, Decimal32 resu private static void AssertEqualAndSameQuantumOrBothNan(Decimal32 expected, Decimal32 result) { - Assert.True((expected.Equals(result) && Decimal32.SameQuantum(expected, result)) || (Decimal32.IsNaN(expected) && Decimal32.IsNaN(result))); + if (!(Decimal32.IsNaN(expected) && Decimal32.IsNaN(result))) + { + AssertEqualAndSameQuantum(expected, result); + } } - [Theory] + [Theory] [MemberData(nameof(Parse_Valid_TestData))] public static void Parse(string value, NumberStyles style, IFormatProvider provider, Decimal32 expected) { From ecbb04c7c8e14c0fced622fb384c56872f60d00e Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Tue, 27 Dec 2022 14:38:39 -0600 Subject: [PATCH 22/39] 33 out of 48 parse tests passing --- .../System.Runtime.Numerics/src/System/Numerics/Decimal32.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index 0fe5dc93581b4f..60669c9c213aed 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -426,14 +426,14 @@ public static Decimal32 Parse(string s) public static Decimal32 Parse(ReadOnlySpan s, IFormatProvider? provider) { IeeeDecimalNumber.ValidateParseStyleFloatingPoint(NumberStyles.Number); // TODO I copied this from NumberFormatInfo to IeeeDecimalNumber, is that ok? - return IeeeDecimalNumber.ParseDecimal32(s, NumberStyles.Number, NumberFormatInfo.GetInstance(provider)); + return IeeeDecimalNumber.ParseDecimal32(s, DefaultParseStyle, NumberFormatInfo.GetInstance(provider)); } /// public static Decimal32 Parse(string s, IFormatProvider? provider) { if (s == null) ThrowHelper.ThrowArgumentNullException("s"); - return IeeeDecimalNumber.ParseDecimal32(s, NumberStyles.Number, NumberFormatInfo.GetInstance(provider)); + return IeeeDecimalNumber.ParseDecimal32(s, DefaultParseStyle, NumberFormatInfo.GetInstance(provider)); } /// From 1030ea6dfe97598e38c6cc177aec2c72ed84883f Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Tue, 27 Dec 2022 16:05:50 -0600 Subject: [PATCH 23/39] 51/51 Parse Tests Pass --- .../src/System/Numerics/IeeeDecimalNumber.cs | 14 ++++++++------ .../tests/Decimal32Tests.cs | 17 +++++++++++------ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs index 63de09004192aa..7861256fdfee85 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs @@ -330,7 +330,7 @@ private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, Nu int digCount = 0; int digEnd = 0; int maxDigCount = number.Digits.Length - 1; - int numberOfTrailingZeros = 0; + // int numberOfTrailingZeros = 0; while (true) { @@ -368,14 +368,15 @@ private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, Nu if (digCount < maxDigCount) { // Handle a case like "53.0". We need to ignore trailing zeros in the fractional part for floating point numbers, so we keep a count of the number of trailing zeros and update digCount later - if (ch == '0') + // Note: I deleted this case because we care about trailing zeros for IEEE decimals + /* if (ch == '0') { numberOfTrailingZeros++; } else { numberOfTrailingZeros = 0; - } + }*/ } digCount++; state |= StateNonZero; @@ -451,14 +452,15 @@ private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, Nu if (/*number.Kind == NumberBufferKind.FloatingPoint && // <- this will always be true */!number.HasNonZeroTail) { // Adjust the number buffer for trailing zeros - int numberOfFractionalDigits = digEnd - number.Scale; + // Note: I deleted this case because we care about trailing zeros for IEEE decimals + /*int numberOfFractionalDigits = digEnd - number.Scale; if (numberOfFractionalDigits > 0) { numberOfTrailingZeros = Math.Min(numberOfTrailingZeros, numberOfFractionalDigits); Debug.Assert(numberOfTrailingZeros >= 0); number.DigitsCount = digEnd - numberOfTrailingZeros; number.Digits[number.DigitsCount] = (byte)('\0'); - } + }*/ } while (true) @@ -638,7 +640,7 @@ internal static unsafe Decimal32 NumberToDecimal32(ref IeeeDecimalNumberBuffer n } // We should either be at the end of the stream or have a non-zero tail - Debug.Assert((c == 0) || !hasZeroTail); + Debug.Assert((mantissa[i] == 0) || !hasZeroTail); if (!hasZeroTail) { diff --git a/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs b/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs index 434f82bf339a68..ae2baeff9a3e00 100644 --- a/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs +++ b/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs @@ -41,8 +41,12 @@ public static IEnumerable Parse_Valid_TestData() yield return new object[] { emptyFormat.NumberDecimalSeparator + "234", defaultStyle, null, new Decimal32(false, -3, 234) }; yield return new object[] { "234" + emptyFormat.NumberDecimalSeparator, defaultStyle, null, new Decimal32(false, 0, 234) }; - yield return new object[] { new string('0', 72) + "3" + new string('0', 38) + emptyFormat.NumberDecimalSeparator, defaultStyle, null, new Decimal32(false, 38, 3) }; // could be wrong - yield return new object[] { new string('0', 73) + "3" + new string('0', 38) + emptyFormat.NumberDecimalSeparator, defaultStyle, null, new Decimal32(false, 38, 3) }; // could be wrong + yield return new object[] { new string('0', 72) + "3" + new string('0', 38) + emptyFormat.NumberDecimalSeparator, defaultStyle, null, new Decimal32(false, 32, 3000000) }; // could be wrong + yield return new object[] { new string('0', 73) + "3" + new string('0', 38) + emptyFormat.NumberDecimalSeparator, defaultStyle, null, new Decimal32(false, 32, 3000000) }; // could be wrong + + // Trailing zeros add sig figs and should be accounted for + yield return new object[] { "1.000", defaultStyle, null, new Decimal32(false, -3, 1000) }; + yield return new object[] { "1.0000000", defaultStyle, null, new Decimal32(false, -6, 1000000) }; // 10^7 + 5. Not exactly representable yield return new object[] { "10000005.0", defaultStyle, invariantFormat, new Decimal32(false, 1, 1000000) }; @@ -54,8 +58,8 @@ public static IEnumerable Parse_Valid_TestData() yield return new object[] { "5.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005", defaultStyle, invariantFormat, new Decimal32(false, -6, 5000000) }; yield return new object[] { "5.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005", defaultStyle, invariantFormat, new Decimal32(false, -6, 5000000) }; yield return new object[] { "5.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005", defaultStyle, invariantFormat, new Decimal32(false, -6, 5000000) }; - yield return new object[] { "5.005000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, new Decimal32(false, -6, 5050000) }; - yield return new object[] { "5.0050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, new Decimal32(false, -6, 5050000) }; + yield return new object[] { "5.005000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, new Decimal32(false, -6, 5005000) }; + yield return new object[] { "5.0050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, new Decimal32(false, -6, 5005000) }; yield return new object[] { "5.0050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, new Decimal32(false, -6, 5005000) }; yield return new object[] { "5005.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", defaultStyle, invariantFormat, new Decimal32(false, -3, 5005000) }; @@ -73,7 +77,8 @@ public static IEnumerable Parse_Valid_TestData() yield return new object[] { "62500", defaultStyle, invariantFormat, new Decimal32(false, 0, 62500) }; yield return new object[] { "123.1", NumberStyles.AllowDecimalPoint, null, new Decimal32(false, -1, 1231) }; - yield return new object[] { "1000.0", NumberStyles.AllowThousands, null, new Decimal32(false, -1, 10000) }; + yield return new object[] { "1,000", NumberStyles.AllowThousands, null, new Decimal32(false, 0, 1000) }; + yield return new object[] { "1,000.0", NumberStyles.AllowThousands | NumberStyles.AllowDecimalPoint, null, new Decimal32(false, -1, 10000) }; yield return new object[] { "123", NumberStyles.Any, emptyFormat, new Decimal32(false, 0, 123) }; yield return new object[] { "123.567", NumberStyles.Any, emptyFormat, new Decimal32(false, -3, 123567) }; @@ -81,7 +86,7 @@ public static IEnumerable Parse_Valid_TestData() yield return new object[] { "$1,000", NumberStyles.Currency, dollarSignCommaSeparatorFormat, new Decimal32(false, 0, 1000) }; yield return new object[] { "$1000", NumberStyles.Currency, dollarSignCommaSeparatorFormat, new Decimal32(false, 0, 1000) }; yield return new object[] { "123.123", NumberStyles.Float, decimalSeparatorFormat, new Decimal32(false, -3, 123123) }; - yield return new object[] { "(123)", NumberStyles.AllowParentheses, decimalSeparatorFormat, new Decimal32(false, 0, 123) }; + yield return new object[] { "(123)", NumberStyles.AllowParentheses, decimalSeparatorFormat, new Decimal32(true, 0, 123) }; // TODO HalfTests and SingleTests have this output -123, but I'm not exactly sure why yield return new object[] { "NaN", NumberStyles.Any, invariantFormat, Decimal32.NaN }; yield return new object[] { "Infinity", NumberStyles.Any, invariantFormat, Decimal32.PositiveInfinity }; From 25488b897c9437cc2d6f0e9f96e6d6aafdb3bfde Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Tue, 27 Dec 2022 16:49:02 -0600 Subject: [PATCH 24/39] All parse tests passing --- .../src/System/Numerics/Decimal32.cs | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index 60669c9c213aed..e4a5b4f83894ad 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -422,10 +422,23 @@ public static Decimal32 Parse(string s) return IeeeDecimalNumber.ParseDecimal32(s, DefaultParseStyle, NumberFormatInfo.CurrentInfo); } + /// + /// Parses a from a in the given . + /// + /// The input to be parsed. + /// The used to parse the input. + /// The equivalent value representing the input string. If the input exceeds Decimal32's range, a or is returned. + public static Decimal32 Parse(string s, NumberStyles style) + { + IeeeDecimalNumber.ValidateParseStyleFloatingPoint(style); + if (s == null) ThrowHelper.ThrowArgumentNullException("s"); + return IeeeDecimalNumber.ParseDecimal32(s, style, NumberFormatInfo.CurrentInfo); + } + /// public static Decimal32 Parse(ReadOnlySpan s, IFormatProvider? provider) { - IeeeDecimalNumber.ValidateParseStyleFloatingPoint(NumberStyles.Number); // TODO I copied this from NumberFormatInfo to IeeeDecimalNumber, is that ok? + IeeeDecimalNumber.ValidateParseStyleFloatingPoint(DefaultParseStyle); // TODO I copied this from NumberFormatInfo to IeeeDecimalNumber, is that ok? return IeeeDecimalNumber.ParseDecimal32(s, DefaultParseStyle, NumberFormatInfo.GetInstance(provider)); } @@ -479,14 +492,10 @@ public static bool TryParse(ReadOnlySpan s, out Decimal32 result) } /// - public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) - { - IeeeDecimalNumber.ValidateParseStyleFloatingPoint(NumberStyles.Number); - return IeeeDecimalNumber.TryParseDecimal32(s, NumberStyles.Number, NumberFormatInfo.GetInstance(provider), out result); - } + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => TryParse(s, DefaultParseStyle, provider, out result); /// - public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => TryParse(s, NumberStyles.Number, provider, out result); + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) => TryParse(s, DefaultParseStyle, provider, out result); /// public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out Decimal32 result) From 57ce29557906a168d142e53f050ed0a19e7e813f Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Tue, 27 Dec 2022 17:04:13 -0600 Subject: [PATCH 25/39] Better test coverage for parsing stuff --- .../tests/Decimal32Tests.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs b/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs index ae2baeff9a3e00..ff2803763e8dc5 100644 --- a/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs +++ b/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs @@ -124,6 +124,9 @@ public static void Parse(string value, NumberStyles style, IFormatProvider provi AssertEqualAndSameQuantum(expected, Decimal32.Parse(value)); } + Assert.True(Decimal32.TryParse(value, provider: provider, out result)); + AssertEqualAndSameQuantum(expected, result); + AssertEqualAndSameQuantum(expected, Decimal32.Parse(value, provider: provider)); } @@ -140,6 +143,7 @@ public static void Parse(string value, NumberStyles style, IFormatProvider provi AssertEqualAndSameQuantum(expected, result); AssertEqualAndSameQuantum(expected, Decimal32.Parse(value)); + AssertEqualAndSameQuantum(expected, Decimal32.Parse(value, style)); AssertEqualAndSameQuantum(expected, Decimal32.Parse(value, style, NumberFormatInfo.CurrentInfo)); } } @@ -187,6 +191,9 @@ public static void Parse_Invalid(string value, NumberStyles style, IFormatProvid Assert.Throws(exceptionType, () => Decimal32.Parse(value)); } + Assert.False(Decimal32.TryParse(value, provider: provider, out result)); + Assert.Equal(default(Decimal32), result); + Assert.Throws(exceptionType, () => Decimal32.Parse(value, provider: provider)); } @@ -242,6 +249,9 @@ public static void Parse_Span_Valid(string value, int offset, int count, NumberS AssertEqualAndSameQuantum(expected, Decimal32.Parse(value.AsSpan(offset, count))); } + Assert.True(Decimal32.TryParse(value.AsSpan(offset, count), provider: provider, out result)); + AssertEqualAndSameQuantum(expected, result); + AssertEqualAndSameQuantum(expected, Decimal32.Parse(value.AsSpan(offset, count), provider: provider)); } @@ -257,10 +267,10 @@ public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatP { if (value != null) { - Assert.Throws(exceptionType, () => float.Parse(value.AsSpan(), style, provider)); + Assert.Throws(exceptionType, () => Decimal32.Parse(value.AsSpan(), style, provider)); - Assert.False(float.TryParse(value.AsSpan(), style, provider, out float result)); - Assert.Equal(0, result); // TODO is this right? + Assert.False(Decimal32.TryParse(value.AsSpan(), style, provider, out Decimal32 result)); + Assert.Equal(default(Decimal32), result); // TODO is this right? } } } From 3656aaaf31d38183e23d16fc4a2404fce2d77cfa Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Wed, 28 Dec 2022 16:36:18 -0600 Subject: [PATCH 26/39] Cleanup --- .../ref/System.Runtime.Numerics.cs | 15 +++++++++++---- .../src/System/Numerics/Decimal32.cs | 9 +++++++-- .../src/System/Numerics/IeeeDecimalNumber.cs | 1 - .../tests/Decimal32Tests.cs | 3 +-- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs index dd63fe15427dce..b6b75cafeb3824 100644 --- a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs +++ b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs @@ -421,6 +421,9 @@ namespace System.Numerics public static System.Numerics.Decimal32 Cos(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 Cosh(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 CosPi(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 CreateChecked(TOther value) where TOther : System.Numerics.INumberBase { throw null; } + public static System.Numerics.Decimal32 CreateSaturating(TOther value) where TOther : System.Numerics.INumberBase { throw null; } + public static System.Numerics.Decimal32 CreateTruncating(TOther value) where TOther : System.Numerics.INumberBase { throw null; } public bool Equals(System.Numerics.Decimal32 other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } public static System.Numerics.Decimal32 Exp(System.Numerics.Decimal32 x) { throw null; } @@ -476,8 +479,10 @@ namespace System.Numerics public static System.Numerics.Decimal32 operator -(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } public static System.Numerics.Decimal32 operator -(System.Numerics.Decimal32 value) { throw null; } public static System.Numerics.Decimal32 operator +(System.Numerics.Decimal32 value) { throw null; } - public static System.Numerics.Decimal32 Parse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } + public static System.Numerics.Decimal32 Parse(System.ReadOnlySpan s, System.Globalization.NumberStyles style = System.Globalization.NumberStyles.AllowDecimalPoint | System.Globalization.NumberStyles.AllowExponent | System.Globalization.NumberStyles.AllowLeadingSign | System.Globalization.NumberStyles.AllowLeadingWhite | System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.AllowTrailingWhite, System.IFormatProvider? provider = null) { throw null; } public static System.Numerics.Decimal32 Parse(System.ReadOnlySpan s, System.IFormatProvider? provider) { throw null; } + public static System.Numerics.Decimal32 Parse(string s) { throw null; } + public static System.Numerics.Decimal32 Parse(string s, System.Globalization.NumberStyles style) { throw null; } public static System.Numerics.Decimal32 Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } public static System.Numerics.Decimal32 Parse(string s, System.IFormatProvider? provider) { throw null; } public static System.Numerics.Decimal32 Pow(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } @@ -496,9 +501,9 @@ namespace System.Numerics static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out System.Numerics.Decimal32 result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out System.Numerics.Decimal32 result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out System.Numerics.Decimal32 result) { throw null; } - static bool System.Numerics.INumberBase.TryConvertToChecked(System.Numerics.Decimal32 value, out TOther result) { throw null; } - static bool System.Numerics.INumberBase.TryConvertToSaturating(System.Numerics.Decimal32 value, out TOther result) { throw null; } - static bool System.Numerics.INumberBase.TryConvertToTruncating(System.Numerics.Decimal32 value, out TOther result) { throw null; } + static bool System.Numerics.INumberBase.TryConvertToChecked(System.Numerics.Decimal32 value, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TOther result) { throw null; } + static bool System.Numerics.INumberBase.TryConvertToSaturating(System.Numerics.Decimal32 value, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TOther result) { throw null; } + static bool System.Numerics.INumberBase.TryConvertToTruncating(System.Numerics.Decimal32 value, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TOther result) { throw null; } public static System.Numerics.Decimal32 Tan(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 Tanh(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 TanPi(System.Numerics.Decimal32 x) { throw null; } @@ -506,8 +511,10 @@ namespace System.Numerics public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format, System.IFormatProvider? provider) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out System.Numerics.Decimal32 result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out System.Numerics.Decimal32 result) { throw null; } + public static bool TryParse(System.ReadOnlySpan s, out System.Numerics.Decimal32 result) { throw null; } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out System.Numerics.Decimal32 result) { throw null; } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out System.Numerics.Decimal32 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.Numerics.Decimal32 result) { throw null; } public bool TryWriteExponentBigEndian(System.Span destination, out int bytesWritten) { throw null; } public bool TryWriteExponentLittleEndian(System.Span destination, out int bytesWritten) { throw null; } public bool TryWriteSignificandBigEndian(System.Span destination, out int bytesWritten) { throw null; } diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index e4a5b4f83894ad..869e9f5bd1f9f2 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -1118,9 +1118,14 @@ public bool Equals(Decimal32 other) public bool TryWriteSignificandBigEndian(Span destination, out int bytesWritten) => throw new NotImplementedException(); public bool TryWriteSignificandLittleEndian(Span destination, out int bytesWritten) => throw new NotImplementedException(); - public static Decimal32 operator +(Decimal32 value) => throw new NotImplementedException(); + /// + public static Decimal32 operator +(Decimal32 value) => value; + + /// public static Decimal32 operator +(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); - public static Decimal32 operator -(Decimal32 value) => throw new NotImplementedException(); + + /// + public static Decimal32 operator -(Decimal32 value) => Negate(value); public static Decimal32 operator -(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); public static Decimal32 operator ++(Decimal32 value) => throw new NotImplementedException(); public static Decimal32 operator --(Decimal32 value) => throw new NotImplementedException(); diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs index 7861256fdfee85..7fe45d82835d50 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs @@ -5,7 +5,6 @@ // If these types lived in the System namespace, these methods would live in Number.Parsing.cs and Number.Formatting.cs, // just like Single, Double, and Half. -using System.Buffers; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; diff --git a/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs b/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs index ff2803763e8dc5..bd813d3a598f3a 100644 --- a/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs +++ b/src/libraries/System.Runtime.Numerics/tests/Decimal32Tests.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Globalization; -using Newtonsoft.Json.Linq; using Xunit; namespace System.Numerics.Tests @@ -270,7 +269,7 @@ public static void Parse_Span_Invalid(string value, NumberStyles style, IFormatP Assert.Throws(exceptionType, () => Decimal32.Parse(value.AsSpan(), style, provider)); Assert.False(Decimal32.TryParse(value.AsSpan(), style, provider, out Decimal32 result)); - Assert.Equal(default(Decimal32), result); // TODO is this right? + Assert.Equal(default(Decimal32), result); } } } From 0ba06726a4c9a219ba54b3157511790e60d6e37a Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Wed, 28 Dec 2022 17:30:38 -0600 Subject: [PATCH 27/39] more cleanup --- .../src/System/Numerics/Decimal32.cs | 46 +++++++++---------- .../src/System/Numerics/IeeeDecimalNumber.cs | 32 +++++++------ 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index 869e9f5bd1f9f2..a27f25363415a2 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -27,7 +27,6 @@ public readonly struct Decimal32 private const NumberStyles DefaultParseStyle = NumberStyles.Float | NumberStyles.AllowThousands; // TODO is this correct? // Constants for manipulating the private bit-representation - // TODO I think adding masks that help us "triage" the type of encoding will be useful. internal const uint SignMask = 0x8000_0000; internal const int SignShift = 31; @@ -40,22 +39,6 @@ public readonly struct Decimal32 internal const uint TrailingSignificandMask = 0x000F_FFFF; internal const int TrailingSignificandWidth = 20; - // TODO figure out if these three are useful, I don't think they are - internal const uint ClassificationMask = 0x7C00_0000; - internal const uint NaNMask = 0x7C00_0000; - internal const uint InfinityMask = 0x7800_0000; - - - // Significands are encoded based on this bit - internal const uint SignificandEncodingTypeMask = 0x0080_0000; - - // Finite numbers are classified based on these bits - internal const uint FiniteNumberClassifictionMask = 0x6000_0000; - - // TODO I think these might be useless in Decimal - /* internal const ushort MinCombination = 0x0000; - internal const ushort MaxCombination = 0x07FF;*/ - internal const sbyte EMax = 96; internal const sbyte EMin = -95; @@ -68,6 +51,20 @@ public readonly struct Decimal32 internal const int MaxSignificand = 9999999; internal const int MinSignificand = -9999999; + // The 5 bits that classify the value as NaN, Infinite, or Finite + // If the Classification bits are set to 11111, the value is NaN + // If the Classification bits are set to 11110, the value is Infinite + // Otherwise, the value is Finite + internal const uint ClassificationMask = 0x7C00_0000; + internal const uint NaNMask = 0x7C00_0000; + internal const uint InfinityMask = 0x7800_0000; + + // If the Classification bits are set to 11XXX, we encode the significand one way. Otherwise, we encode it a different way + internal const uint FiniteNumberClassificationMask = 0x6000_0000; + + // Finite significands are encoded in two different ways. Encoding type can be selected based on whether or not this bit is set in the decoded significand. + internal const uint SignificandEncodingTypeMask = 0x0080_0000; + // Constants representing the private bit-representation for various default values. // See either IEEE-754 2019 section 3.5 or https://en.wikipedia.org/wiki/Decimal32_floating-point_format for a breakdown of the encoding. @@ -162,8 +159,10 @@ public readonly struct Decimal32 // c. Significand, set to 1. // // Encoded value: 1 x 10^0 + private const uint PositiveOneBits = 0x3280_0001; private const uint NegativeOneBits = SignMask | PositiveOneBits; + /* private const uint EBits = 0; // TODO private const uint PiBits = 0; // TODO @@ -199,9 +198,9 @@ public readonly struct Decimal32 public static Decimal32 Zero => new Decimal32(PositiveZeroBits); // -0E-101 - public static Decimal32 AdditiveIdentity => new Decimal32(PositiveZeroBits); // TODO do we want to make sure this is a zero such that the quantum of any other value is preserved on addition? + public static Decimal32 AdditiveIdentity => new Decimal32(PositiveZeroBits); // TODO make sure this is a zero such that the quantum of any other value is preserved on addition - public static Decimal32 MultiplicativeIdentity => new Decimal32(PositiveZeroBits); // TODO do we want to make sure this is a zero such that the quantum of any other value is preserved on addition? + public static Decimal32 MultiplicativeIdentity => new Decimal32(PositiveZeroBits); // TODO make sure this is a zero such that the quantum of any other value is preserved on multiplication internal readonly uint _value; // TODO: Single places this at the top, Half places it here. Also, Single has this as private, Half has it as internal. What do we want? @@ -233,8 +232,6 @@ internal Decimal32(bool sign, sbyte q, uint c) // We are encoding a significand that has the most significand 4 bits set to 0xyz combination |= (uint)(q + ExponentBias) << 3; combination |= 0b0111 & (c >> TrailingSignificandWidth); // combination = (biased_exponent, xyz) - - } else { @@ -276,7 +273,6 @@ internal uint TrailingSignificand { get { - Debug.Assert(IsFinite(this)); // TODO NaN and Inf might want to use this return _value & TrailingSignificandMask; } } @@ -287,7 +283,7 @@ internal static byte ExtractBiasedExponentFromBits(uint bits) ushort combination = (ushort)((bits >> CombinationShift) & ShiftedCombinationMask); // Two types of encodings for finite numbers - if ((bits & FiniteNumberClassifictionMask) == FiniteNumberClassifictionMask) + if ((bits & FiniteNumberClassificationMask) == FiniteNumberClassificationMask) { // G0 and G1 are 11, exponent is stored in G2:G(CombinationWidth - 1) return (byte)(combination >> 1); @@ -299,14 +295,14 @@ internal static byte ExtractBiasedExponentFromBits(uint bits) } } - // TODO this returns garbage for Inf and NaN + // returns garbage for infinity and NaN, TODO maybe fix this internal static uint ExtractSignificandFromBits(uint bits) { ushort combination = (ushort)((bits >> CombinationShift) & ShiftedCombinationMask); // Two types of encodings for finite numbers uint significand; - if ((bits & FiniteNumberClassifictionMask) == FiniteNumberClassifictionMask) + if ((bits & FiniteNumberClassificationMask) == FiniteNumberClassificationMask) { // G0 and G1 are 11, 4 MSBs of significand are 100x, where x is G(CombinationWidth) significand = (uint)(0b1000 | (combination & 0b1)); diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs index 7fe45d82835d50..5319e28ee8caf2 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs @@ -75,14 +75,14 @@ public void CheckConsistency() #endif // DEBUG } - public byte* GetDigitsPointer() // TODO this is complaining that the method could be static, but it is wrong + public byte* GetDigitsPointer() { // This is safe to do since we are a ref struct return (byte*)(Unsafe.AsPointer(ref Digits[0])); } // - // Code coverage note: This only exists so that Number displays nicely in the VS watch window. So yes, I know it works. + // Code coverage note: This only exists so that IeeeDecimalNumber displays nicely in the VS watch window. So yes, I know it works. // public override string ToString() { @@ -116,7 +116,6 @@ public override string ToString() // IeeeDecimalNumber Parsing - // TODO potentially rewrite this description // The Parse methods provided by the numeric classes convert a // string to a numeric value. The optional style parameter specifies the // permitted style of the numeric string. It must be a combination of bit flags @@ -132,13 +131,12 @@ public override string ToString() // specified. Note, however, that the Parse methods do not accept // NaNs or Infinities. - // Max and Min Exponent assuming the value is in the form 0.Mantissa x 10^Exponent private const int Decimal32MaxExponent = Decimal32.MaxQExponent + Decimal32.Precision; // TODO check this - private const int Decimal32MinExponent = Decimal32.MinQExponent + Decimal32.Precision; // TODO check this, probably wrong + private const int Decimal32MinExponent = Decimal32.MinQExponent + Decimal32.Precision; // TODO check this, possibly wrong [DoesNotReturn] - internal static void ThrowFormatException(ReadOnlySpan value) => throw new FormatException(/*SR.Format(SR.Format_InvalidStringWithValue,*/ value.ToString()/*)*/); + internal static void ThrowFormatException(ReadOnlySpan value) => throw new FormatException(/*SR.Format(SR.Format_InvalidStringWithValue,*/ value.ToString()/*)*/); // TODO get this to work internal static Decimal32 ParseDecimal32(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info) { @@ -246,7 +244,7 @@ private static bool TrailingZeros(ReadOnlySpan value, int index) => // For compatibility, we need to allow trailing zeros at the end of a number string value.Slice(index).IndexOfAnyExcept('\0') < 0; - // This is almost a direct copy paste of the one in Number.Parsing.cs + // Note: this is copy pasted and adjusted from Number.Parsing.cs in System.Private.CoreLib private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, NumberStyles styles, ref IeeeDecimalNumberBuffer number, NumberFormatInfo info) { Debug.Assert(str != null); @@ -329,7 +327,7 @@ private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, Nu int digCount = 0; int digEnd = 0; int maxDigCount = number.Digits.Length - 1; - // int numberOfTrailingZeros = 0; + // int numberOfTrailingZeros = 0; TODO delete this comment while (true) { @@ -342,6 +340,7 @@ private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, Nu if (digCount < maxDigCount) { number.Digits[digCount] = (byte)(ch); + // TODO delete this comment //if ((ch != '0') || (number.Kind != NumberBufferKind.Integer)) // number.Kind will always not be Integer //{ digEnd = digCount + 1; @@ -367,7 +366,7 @@ private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, Nu if (digCount < maxDigCount) { // Handle a case like "53.0". We need to ignore trailing zeros in the fractional part for floating point numbers, so we keep a count of the number of trailing zeros and update digCount later - // Note: I deleted this case because we care about trailing zeros for IEEE decimals + // // TODO delete this comment: I removed this case because we care about trailing zeros for IEEE decimals /* if (ch == '0') { numberOfTrailingZeros++; @@ -448,19 +447,24 @@ private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, Nu } } - if (/*number.Kind == NumberBufferKind.FloatingPoint && // <- this will always be true */!number.HasNonZeroTail) + + // TODO delete this comment: I removed this case because we care about trailing zeros for IEEE decimals + /* + if (number.Kind == NumberBufferKind.FloatingPoint && + !number.HasNonZeroTail) { // Adjust the number buffer for trailing zeros - // Note: I deleted this case because we care about trailing zeros for IEEE decimals - /*int numberOfFractionalDigits = digEnd - number.Scale; + + int numberOfFractionalDigits = digEnd - number.Scale; if (numberOfFractionalDigits > 0) { numberOfTrailingZeros = Math.Min(numberOfTrailingZeros, numberOfFractionalDigits); Debug.Assert(numberOfTrailingZeros >= 0); number.DigitsCount = digEnd - numberOfTrailingZeros; number.Digits[number.DigitsCount] = (byte)('\0'); - }*/ + } } + */ while (true) { @@ -694,6 +698,6 @@ static void ThrowInvalid(NumberStyles value) } } - // IeeeDecimalNumber Formatting + // IeeeDecimalNumber Formatting TODO } } From 549cc0f129a235f564e931cc1428f5159ae9ce5d Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Fri, 20 Jan 2023 20:25:34 -0600 Subject: [PATCH 28/39] Organized Decimal32.cs --- .../src/System/Numerics/Decimal32.cs | 979 +++++++++++++----- 1 file changed, 714 insertions(+), 265 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index a27f25363415a2..acbc987edc59cc 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -26,7 +26,9 @@ public readonly struct Decimal32 private const NumberStyles DefaultParseStyle = NumberStyles.Float | NumberStyles.AllowThousands; // TODO is this correct? + // // Constants for manipulating the private bit-representation + // internal const uint SignMask = 0x8000_0000; internal const int SignShift = 31; @@ -168,43 +170,11 @@ public readonly struct Decimal32 private const uint PiBits = 0; // TODO private const uint TauBits = 0; // TODO*/ - // Well-defined and commonly used values - - public static Decimal32 MaxValue => new Decimal32(MaxValueBits); // 9.999999E90 - - public static Decimal32 MinValue => new Decimal32(MinValueBits); // -9.999999E90 - - public static Decimal32 Epsilon => new Decimal32(EpsilonBits); // 1E-101 - - public static Decimal32 NaN => new Decimal32(QNanBits); // 0.0 / 0.0 - - public static Decimal32 NegativeInfinity => new Decimal32(NegativeInfinityBits); // -1.0 / 0.0 - - public static Decimal32 NegativeZero => new Decimal32(NegativeZeroBits); // -0E-101 - - public static Decimal32 PositiveInfinity => new Decimal32(PositiveInfinityBits); // 1.0 / 0.0 - - public static Decimal32 NegativeOne => new Decimal32(NegativeOneBits); // -1E0 - - public static Decimal32 E => throw new NotImplementedException(); - - public static Decimal32 Pi => throw new NotImplementedException(); - - public static Decimal32 Tau => throw new NotImplementedException(); - - public static Decimal32 One => new Decimal32(PositiveOneBits); // 1E0 - - public static int Radix => 10; - - public static Decimal32 Zero => new Decimal32(PositiveZeroBits); // -0E-101 - - public static Decimal32 AdditiveIdentity => new Decimal32(PositiveZeroBits); // TODO make sure this is a zero such that the quantum of any other value is preserved on addition - - public static Decimal32 MultiplicativeIdentity => new Decimal32(PositiveZeroBits); // TODO make sure this is a zero such that the quantum of any other value is preserved on multiplication - internal readonly uint _value; // TODO: Single places this at the top, Half places it here. Also, Single has this as private, Half has it as internal. What do we want? - // Private Constructors + // + // Internal Constructors and Decoders + // internal Decimal32(uint value) { @@ -322,87 +292,6 @@ private static uint StripSign(Decimal32 value) return value._value & ~SignMask; } - /// - public static Decimal32 Abs(Decimal32 value) - { - return new Decimal32(value._value & ~SignMask); - } - - public static Decimal32 Acos(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Acosh(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 AcosPi(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Asin(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Asinh(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 AsinPi(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Atan(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Atan2(Decimal32 y, Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Atan2Pi(Decimal32 y, Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Atanh(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 AtanPi(Decimal32 x) => throw new NotImplementedException(); - /// - public static Decimal32 BitDecrement(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 BitIncrement(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Cbrt(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Cos(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Cosh(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 CosPi(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Exp(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Exp10(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Exp2(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 FusedMultiplyAdd(Decimal32 left, Decimal32 right, Decimal32 addend) => throw new NotImplementedException(); - public static Decimal32 Hypot(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); - public static Decimal32 Ieee754Remainder(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); - public static int ILogB(Decimal32 x) => throw new NotImplementedException(); - public static bool IsCanonical(Decimal32 value) => throw new NotImplementedException(); - public static bool IsComplexNumber(Decimal32 value) => throw new NotImplementedException(); - public static bool IsEvenInteger(Decimal32 value) => throw new NotImplementedException(); - public static bool IsFinite(Decimal32 value) - { - return StripSign(value) < PositiveInfinityBits; - } - public static bool IsImaginaryNumber(Decimal32 value) => throw new NotImplementedException(); - public static bool IsInfinity(Decimal32 value) - { - return (value._value & ClassificationMask) == InfinityMask; - } - public static bool IsInteger(Decimal32 value) => throw new NotImplementedException(); - public static bool IsNaN(Decimal32 value) - { - return (value._value & ClassificationMask) == NaNMask; - } - public static bool IsNegative(Decimal32 value) - { - return (int)(value._value) < 0; - } - public static bool IsNegativeInfinity(Decimal32 value) - { - return IsInfinity(value) && IsNegative(value); - } - public static bool IsNormal(Decimal32 value) => throw new NotImplementedException(); - public static bool IsOddInteger(Decimal32 value) => throw new NotImplementedException(); - public static bool IsPositive(Decimal32 value) - { - return (int)(value._value) >= 0; - } - public static bool IsPositiveInfinity(Decimal32 value) - { - return IsInfinity(value) && IsPositive(value); - } - public static bool IsRealNumber(Decimal32 value) => throw new NotImplementedException(); - public static bool IsSubnormal(Decimal32 value) => throw new NotImplementedException(); - public static bool IsZero(Decimal32 value) - { - return value.Significand == 0; - } - public static Decimal32 Log(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Log(Decimal32 x, Decimal32 newBase) => throw new NotImplementedException(); - public static Decimal32 Log10(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Log2(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 MaxMagnitude(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); - public static Decimal32 MaxMagnitudeNumber(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); - public static Decimal32 MinMagnitude(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); - public static Decimal32 MinMagnitudeNumber(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); - // // Parsing (INumberBase, IParsable, ISpanParsable) // @@ -514,34 +403,550 @@ public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, I return IeeeDecimalNumber.TryParseDecimal32(s, style, NumberFormatInfo.GetInstance(provider), out result); } - public static Decimal32 Pow(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); - public static Decimal32 Quantize(Decimal32 x, Decimal32 y) - { - throw new NotImplementedException(); - } - public static Decimal32 Quantum(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 RootN(Decimal32 x, int n) => throw new NotImplementedException(); - public static Decimal32 Round(Decimal32 x, int digits, MidpointRounding mode) => throw new NotImplementedException(); - public static bool SameQuantum(Decimal32 x, Decimal32 y) + // + // Misc. Methods (IComparable, IEquatable) + // + + /// + /// Compares this object to another object, returning an integer that indicates the relationship. + /// + /// A value less than zero if this is less than , zero if this is equal to , or a value greater than zero if this is greater than . + /// Thrown when is not of type . + public int CompareTo(object? obj) => throw new NotImplementedException(); + + /// + /// Compares this object to another object, returning an integer that indicates the relationship. + /// + /// A value less than zero if this is less than , zero if this is equal to , or a value greater than zero if this is greater than . + public int CompareTo(Decimal32 other) => throw new NotImplementedException(); + + /// + /// Returns a value that indicates whether this instance is equal to a specified . + /// + public override bool Equals([NotNullWhen(true)] object? obj) + { + return (obj is Decimal32 other) && Equals(other); + } + + /// + /// Returns a value that indicates whether this instance is equal to a specified value. + /// + public bool Equals(Decimal32 other) + { + return this == other + || (IsNaN(this) && IsNaN(other)); + } + + /// + /// Serves as the default hash function. + /// + public override int GetHashCode() + { + // TODO we know that NaNs and Zeros should hash the same. Should values of the same cohort have the same hash? + throw new NotImplementedException(); + } + + // + // Formatting (IFormattable, ISpanFormattable) + // + + /// + /// Returns a string representation of the current value. + /// + public override string ToString() + { + throw new NotImplementedException(); + } + + /// + /// Returns a string representation of the current value using the specified . + /// + public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format) + { + throw new NotImplementedException(); + } + + /// + /// Returns a string representation of the current value with the specified . + /// + public string ToString(IFormatProvider? provider) + { + throw new NotImplementedException(); + } + + /// + /// Returns a string representation of the current value using the specified and . + /// + public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format, IFormatProvider? provider) // TODO the interface calls this second param "formatProvider". Which do we want? + { + // Temporary Formatting for debugging + if (IsNaN(this)) + { + return "NaN"; + } + else if (IsPositiveInfinity(this)) + { + return "Infinity"; + } + else if (IsNegativeInfinity(this)) + { + return "-Infinity"; + } + + return (IsPositive(this) ? "" : "-") + Significand.ToString() + "E" + Exponent.ToString(); + } + + /// + /// Tries to format the value of the current Decimal32 instance into the provided span of characters. + /// + /// When this method returns, this instance's value formatted as a span of characters. + /// When this method returns, the number of characters that were written in . + /// A span containing the characters that represent a standard or custom format string that defines the acceptable format for . + /// An optional object that supplies culture-specific formatting information for . + /// + public bool TryFormat(Span destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan format = default, IFormatProvider? provider = null) + { + throw new NotImplementedException(); + } + + + // + // Explicit Convert To Decimal32 TODO + // + + // + // Explicit Convert From Decimal32 TODO + // + + // + // Implicit Convert To Decimal32 TODO + // + + // + // Implicit Convert From Decimal32 TODO + // + + // + // IAdditionOperators + // + + /// + public static Decimal32 operator +(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + + // + // IAdditiveIdentity + // + + /// + static Decimal32 IAdditiveIdentity.AdditiveIdentity => new Decimal32(PositiveZeroBits); // TODO make sure this is a zero such that the quantum of any other value is preserved on addition + + + // + // IComparisonOperators + // + + /// + public static bool operator <(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + + /// + public static bool operator >(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + + /// + public static bool operator <=(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + + /// + public static bool operator >=(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + + // + // IDecimalFloatingPointIeee754 + // + + /// + public static Decimal32 Quantize(Decimal32 x, Decimal32 y) + { + throw new NotImplementedException(); + } + + /// + public static Decimal32 Quantum(Decimal32 x) => throw new NotImplementedException(); + + /// + public static bool SameQuantum(Decimal32 x, Decimal32 y) + { + return x.Exponent == y.Exponent + || (IsInfinity(x) && IsInfinity(y)) + || (IsNaN(x) && IsNaN(y)); + } + + // + // IDecrementOperators + // + + /// + public static Decimal32 operator --(Decimal32 value) => throw new NotImplementedException(); + + // + // IDivisionOperators + // + + /// + public static Decimal32 operator /(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + + // + // IEqualityOperators + // + + // Fast access for 10^n where n is 0:(Precision - 1) + private static readonly uint[] s_powers10 = new uint[] { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000 + }; + + /// + public static bool operator ==(Decimal32 left, Decimal32 right) // TODO we can probably do this faster + { + if (IsNaN(left) || IsNaN(right)) + { + // IEEE defines that NaN is not equal to anything, including itself. + return false; + } + + if (IsZero(left) && IsZero(right)) + { + // IEEE defines that positive and negative zero are equivalent. + return true; + } + + bool sameSign = IsPositive(left) == IsPositive(right); + + if (IsInfinity(left) || IsInfinity(right)) + { + if (IsInfinity(left) && IsInfinity(right) && sameSign) + { + return true; + } + else + { + return false; + } + } + + // IEEE defines that two values of the same cohort are numerically equivalent + + uint leftSignificand = left.Significand; + uint rightSignificand = right.Significand; + sbyte leftQ = left.Exponent; + sbyte rightQ = right.Exponent; + int diffQ = leftQ - rightQ; + + bool sameNumericalValue = false; + if (int.Abs(diffQ) < Precision) // If diffQ is >= Precision, the non-zero finite values have exponents too far apart for them to possibly be equal + { + try + { + if (diffQ < 0) + { + // leftQ is smaller than rightQ, scale leftSignificand + leftSignificand = checked(leftSignificand * s_powers10[int.Abs(diffQ)]); + } + else + { + // rightQ is smaller than (or equal to) leftQ, scale rightSignificand + rightSignificand = checked(rightSignificand * s_powers10[diffQ]); + } + } + catch + { + // multiplication overflowed, return false + return false; + } + + if (leftSignificand == rightSignificand) + { + sameNumericalValue = true; + } + } + + return sameNumericalValue && sameSign; + } + + /// + public static bool operator !=(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + + // + // IExponentialFunctions + // + + /// + public static Decimal32 Exp(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 ExpM1(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Exp2(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Exp2M1(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Exp10(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Exp10M1(Decimal32 x) => throw new NotImplementedException(); + + // + // IFloatingPoint + // + + /// + public static Decimal32 Ceiling(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Floor(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Round(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Round(Decimal32 x, int digits) => throw new NotImplementedException(); + + /// + public static Decimal32 Round(Decimal32 x, MidpointRounding mode) => throw new NotImplementedException(); + + /// + public static Decimal32 Round(Decimal32 x, int digits, MidpointRounding mode) => throw new NotImplementedException(); + + /// + public static Decimal32 Truncate(Decimal32 x) => throw new NotImplementedException(); + + /// + int IFloatingPoint.GetExponentByteCount() => throw new NotImplementedException(); + + /// + int IFloatingPoint.GetExponentShortestBitLength() => throw new NotImplementedException(); + + /// + int IFloatingPoint.GetSignificandBitLength() => throw new NotImplementedException(); + + /// + int IFloatingPoint.GetSignificandByteCount() => throw new NotImplementedException(); + + /// + bool IFloatingPoint.TryWriteExponentBigEndian(Span destination, out int bytesWritten) => throw new NotImplementedException(); + + /// + bool IFloatingPoint.TryWriteExponentLittleEndian(Span destination, out int bytesWritten) => throw new NotImplementedException(); + + /// + bool IFloatingPoint.TryWriteSignificandBigEndian(Span destination, out int bytesWritten) => throw new NotImplementedException(); + + /// + bool IFloatingPoint.TryWriteSignificandLittleEndian(Span destination, out int bytesWritten) => throw new NotImplementedException(); + + // + // IFloatingPointConstants + // + + /// + public static Decimal32 E => throw new NotImplementedException(); + + /// + public static Decimal32 Pi => throw new NotImplementedException(); + + /// + public static Decimal32 Tau => throw new NotImplementedException(); + + // + // IFloatingPointIeee754 + // + + /// + public static Decimal32 Epsilon => new Decimal32(EpsilonBits); // 1E-101 + + /// + public static Decimal32 NaN => new Decimal32(QNanBits); // 0.0 / 0.0 + + /// + public static Decimal32 NegativeInfinity => new Decimal32(NegativeInfinityBits); // -1.0 / 0.0 + + /// + public static Decimal32 NegativeZero => new Decimal32(NegativeZeroBits); // -0E-101 + + /// + public static Decimal32 PositiveInfinity => new Decimal32(PositiveInfinityBits); // 1.0 / 0.0 + + /// + public static Decimal32 Atan2(Decimal32 y, Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Atan2Pi(Decimal32 y, Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 BitDecrement(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 BitIncrement(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 FusedMultiplyAdd(Decimal32 left, Decimal32 right, Decimal32 addend) => throw new NotImplementedException(); + + /// + public static Decimal32 Ieee754Remainder(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + + /// + public static int ILogB(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 ReciprocalEstimate(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 ReciprocalSqrtEstimate(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 ScaleB(Decimal32 x, int n) => throw new NotImplementedException(); + + // /// + // public static Decimal32 Compound(Half x, Decimal32 n) => throw new NotImplementedException(); + + // + // IHyperbolicFunctions + // + + /// + public static Decimal32 Acosh(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Asinh(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Atanh(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Cosh(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Sinh(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Tanh(Decimal32 x) => throw new NotImplementedException(); + + // + // IIncrementOperators + // + + /// + public static Decimal32 operator ++(Decimal32 value) => throw new NotImplementedException(); + + // + // ILogarithmicFunctions + // + + /// + public static Decimal32 Log(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Log(Decimal32 x, Decimal32 newBase) => throw new NotImplementedException(); + + /// + public static Decimal32 Log10(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 LogP1(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Log2(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Log2P1(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Log10P1(Decimal32 x) => throw new NotImplementedException(); + + // + // IMinMaxValue + // + + /// + public static Decimal32 MaxValue => new Decimal32(MaxValueBits); // 9.999999E90 + + /// + public static Decimal32 MinValue => new Decimal32(MinValueBits); // -9.999999E90 + + // + // IModulusOperators + // + + /// + public static Decimal32 operator %(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + + // + // IMultiplicativeIdentity + // + + /// + public static Decimal32 MultiplicativeIdentity => new Decimal32(PositiveZeroBits); // TODO make sure this is a zero such that the quantum of any other value is preserved on multiplication + + // + // IMultiplyOperators + // + + /// + public static Decimal32 operator *(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + + // + // INumber + // + + /// + public static Decimal32 Clamp(Decimal32 value, Decimal32 min, Decimal32 max) => throw new NotImplementedException(); + + /// + public static Decimal32 CopySign(Decimal32 value, Decimal32 sign) => throw new NotImplementedException(); + + /// + public static Decimal32 Max(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + + /// + public static Decimal32 MaxNumber(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + + /// + public static Decimal32 Min(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + + /// + public static Decimal32 MinNumber(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + + /// + public static int Sign(Decimal32 value) => throw new NotImplementedException(); + + + // + // INumberBase (well defined/commonly used values) + // + + /// + public static Decimal32 One => new Decimal32(PositiveOneBits); // 1E0 + + /// + static int INumberBase.Radix => 10; // TODO this should be exposed implicitly as it is required by IEEE + + /// + public static Decimal32 Zero => new Decimal32(PositiveZeroBits); // -0E-101 + + /// + public static Decimal32 Abs(Decimal32 value) { - return x.Exponent == y.Exponent - || (IsInfinity(x) && IsInfinity(y)) - || (IsNaN(x) && IsNaN(y)); + return new Decimal32(value._value & ~SignMask); } - public static Decimal32 ScaleB(Decimal32 x, int n) => throw new NotImplementedException(); - public static Decimal32 Sin(Decimal32 x) => throw new NotImplementedException(); - public static (Decimal32 Sin, Decimal32 Cos) SinCos(Decimal32 x) => throw new NotImplementedException(); - public static (Decimal32 SinPi, Decimal32 CosPi) SinCosPi(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Sinh(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 SinPi(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Sqrt(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Tan(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 Tanh(Decimal32 x) => throw new NotImplementedException(); - public static Decimal32 TanPi(Decimal32 x) => throw new NotImplementedException(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Decimal32 CreateChecked(TOther value) // TODO these are copy-pastes of the DIM. Do we still want them? + public static Decimal32 CreateChecked(TOther value) where TOther : INumberBase { Decimal32 result; @@ -596,6 +1001,98 @@ public static Decimal32 CreateTruncating(TOther value) return result; } + /// + static bool INumberBase.IsCanonical(Decimal32 value) => throw new NotImplementedException(); // TODO this should be exposed implicitly as it is required by IEEE + + /// + static bool INumberBase.IsComplexNumber(Decimal32 value) => throw new NotImplementedException(); + + /// + public static bool IsEvenInteger(Decimal32 value) => throw new NotImplementedException(); + + /// + public static bool IsFinite(Decimal32 value) + { + return StripSign(value) < PositiveInfinityBits; + } + + /// + static bool INumberBase.IsImaginaryNumber(Decimal32 value) => throw new NotImplementedException(); + + /// + public static bool IsInfinity(Decimal32 value) + { + return (value._value & ClassificationMask) == InfinityMask; + } + + /// + public static bool IsInteger(Decimal32 value) => throw new NotImplementedException(); + + /// + public static bool IsNaN(Decimal32 value) + { + return (value._value & ClassificationMask) == NaNMask; + } + + /// + public static bool IsNegative(Decimal32 value) + { + return (int)(value._value) < 0; + } + + /// + public static bool IsNegativeInfinity(Decimal32 value) + { + return IsInfinity(value) && IsNegative(value); + } + + /// + public static bool IsNormal(Decimal32 value) => throw new NotImplementedException(); + + /// + public static bool IsOddInteger(Decimal32 value) => throw new NotImplementedException(); + + /// + public static bool IsPositive(Decimal32 value) + { + return (int)(value._value) >= 0; + } + + /// + public static bool IsPositiveInfinity(Decimal32 value) + { + return IsInfinity(value) && IsPositive(value); + } + + /// + public static bool IsRealNumber(Decimal32 value) => throw new NotImplementedException(); + + /// + public static bool IsSubnormal(Decimal32 value) => throw new NotImplementedException(); + + /// + static bool INumberBase.IsZero(Decimal32 value) // TODO this should be exposed implicitly as it is required by IEEE (see private function below) + { + return value.Significand == 0; + } + + private static bool IsZero(Decimal32 value) + { + return value.Significand == 0; + } + + /// + public static Decimal32 MaxMagnitude(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + + /// + public static Decimal32 MaxMagnitudeNumber(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + + /// + public static Decimal32 MinMagnitude(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + + /// + public static Decimal32 MinMagnitudeNumber(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool INumberBase.TryConvertFromChecked(TOther value, out Decimal32 result) => TryConvertFromChecked(value, out result); @@ -1096,150 +1593,102 @@ static bool INumberBase.TryConvertToTruncating(Decimal32 valu } } - public int CompareTo(Decimal32 other) => throw new NotImplementedException(); - public int CompareTo(object? obj) => throw new NotImplementedException(); - public bool Equals(Decimal32 other) - { - return this == other - || (IsNaN(this) && IsNaN(other)); - } - public int GetExponentByteCount() => throw new NotImplementedException(); - public int GetExponentShortestBitLength() => throw new NotImplementedException(); - public int GetSignificandBitLength() => throw new NotImplementedException(); - public int GetSignificandByteCount() => throw new NotImplementedException(); - public TypeCode GetTypeCode() => throw new NotImplementedException(); - public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) => throw new NotImplementedException(); - public bool TryWriteExponentBigEndian(Span destination, out int bytesWritten) => throw new NotImplementedException(); - public bool TryWriteExponentLittleEndian(Span destination, out int bytesWritten) => throw new NotImplementedException(); - public bool TryWriteSignificandBigEndian(Span destination, out int bytesWritten) => throw new NotImplementedException(); - public bool TryWriteSignificandLittleEndian(Span destination, out int bytesWritten) => throw new NotImplementedException(); + // + // IPowerFunctions + // - /// - public static Decimal32 operator +(Decimal32 value) => value; + /// + public static Decimal32 Pow(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); - /// - public static Decimal32 operator +(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + // + // IRootFunctions + // - /// - public static Decimal32 operator -(Decimal32 value) => Negate(value); + /// + public static Decimal32 Cbrt(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 Hypot(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + + /// + public static Decimal32 RootN(Decimal32 x, int n) => throw new NotImplementedException(); + + /// + public static Decimal32 Sqrt(Decimal32 x) => throw new NotImplementedException(); + + // + // ISignedNumber + // + + /// + public static Decimal32 NegativeOne => new Decimal32(NegativeOneBits); // -1E0 + + // + // ISubtractionOperators + // + + /// public static Decimal32 operator -(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); - public static Decimal32 operator ++(Decimal32 value) => throw new NotImplementedException(); - public static Decimal32 operator --(Decimal32 value) => throw new NotImplementedException(); - public static Decimal32 operator *(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); - public static Decimal32 operator /(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); - public static Decimal32 operator %(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); - // Fast access for 10^n where n is 0:(Precision - 1) - private static readonly uint[] s_powers10 = new uint[] { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000 - }; + // + // ITrigonometricFunctions + // - public static bool operator ==(Decimal32 left, Decimal32 right) // TODO we can probably do this faster - { - if (IsNaN(left) || IsNaN(right)) - { - // IEEE defines that NaN is not equal to anything, including itself. - return false; - } + /// + public static Decimal32 Acos(Decimal32 x) => throw new NotImplementedException(); - if (IsZero(left) && IsZero(right)) - { - // IEEE defines that positive and negative zero are equivalent. - return true; - } + /// + public static Decimal32 AcosPi(Decimal32 x) => throw new NotImplementedException(); - bool sameSign = IsPositive(left) == IsPositive(right); + /// + public static Decimal32 Asin(Decimal32 x) => throw new NotImplementedException(); - if (IsInfinity(left) || IsInfinity(right)) - { - if (IsInfinity(left) && IsInfinity(right) && sameSign) - { - return true; - } - else - { - return false; - } - } + /// + public static Decimal32 AsinPi(Decimal32 x) => throw new NotImplementedException(); - // IEEE defines that two values of the same cohort are numerically equivalent + /// + public static Decimal32 Atan(Decimal32 x) => throw new NotImplementedException(); - uint leftSignificand = left.Significand; - uint rightSignificand = right.Significand; - sbyte leftQ = left.Exponent; - sbyte rightQ = right.Exponent; - int diffQ = leftQ - rightQ; + /// + public static Decimal32 AtanPi(Decimal32 x) => throw new NotImplementedException(); - bool sameNumericalValue = false; - if (int.Abs(diffQ) < Precision) // If diffQ is >= Precision, the non-zero finite values have exponents too far apart for them to possibly be equal - { - try - { - if (diffQ < 0) - { - // leftQ is smaller than rightQ, scale leftSignificand - leftSignificand = checked(leftSignificand * s_powers10[int.Abs(diffQ)]); - } - else - { - // rightQ is smaller than (or equal to) leftQ, scale rightSignificand - rightSignificand = checked(rightSignificand * s_powers10[diffQ]); - } - } - catch - { - // multiplication overflowed, return false - return false; - } + /// + public static Decimal32 Cos(Decimal32 x) => throw new NotImplementedException(); - if (leftSignificand == rightSignificand) - { - sameNumericalValue = true; - } - } + /// + public static Decimal32 CosPi(Decimal32 x) => throw new NotImplementedException(); - return sameNumericalValue && sameSign; - } - public static bool operator !=(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); - public static bool operator <(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); - public static bool operator >(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); - public static bool operator <=(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); - public static bool operator >=(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); + /// + public static Decimal32 Sin(Decimal32 x) => throw new NotImplementedException(); - public override bool Equals([NotNullWhen(true)] object? obj) - { - return obj is Decimal32 && Equals((Decimal32)obj); - } + /// + public static (Decimal32 Sin, Decimal32 Cos) SinCos(Decimal32 x) => throw new NotImplementedException(); - public override int GetHashCode() - { - throw new NotImplementedException(); - } + /// + public static (Decimal32 SinPi, Decimal32 CosPi) SinCosPi(Decimal32 x) => throw new NotImplementedException(); - public string ToString(string? format, IFormatProvider? formatProvider) - { - // Temporary Formatting for debugging - if (IsNaN(this)) - { - return "NaN"; - } - else if (IsPositiveInfinity(this)) - { - return "Infinity"; - } - else if (IsNegativeInfinity(this)) - { - return "-Infinity"; - } + /// + public static Decimal32 SinPi(Decimal32 x) => throw new NotImplementedException(); - return (IsPositive(this) ? "" : "-") + Significand.ToString() + "E" + Exponent.ToString(); - } + /// + public static Decimal32 Tan(Decimal32 x) => throw new NotImplementedException(); + + /// + public static Decimal32 TanPi(Decimal32 x) => throw new NotImplementedException(); + + // + // IUnaryNegationOperators + // + + /// + public static Decimal32 operator -(Decimal32 value) => Negate(value); + + // + // IUnaryPlusOperators + // + + /// + public static Decimal32 operator +(Decimal32 value) => value; // IEEE 754 specifies NaNs to be propagated internal static Decimal32 Negate(Decimal32 value) From 16919962cee0581b4bf2252d2383d0a292842c7f Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Fri, 20 Jan 2023 20:28:17 -0600 Subject: [PATCH 29/39] Rename the parsing file --- .../System.Runtime.Numerics/src/System.Runtime.Numerics.csproj | 2 +- .../{IeeeDecimalNumber.cs => IeeeDecimalNumber.Parsing.cs} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/libraries/System.Runtime.Numerics/src/System/Numerics/{IeeeDecimalNumber.cs => IeeeDecimalNumber.Parsing.cs} (100%) diff --git a/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj b/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj index be5c8efa5eab43..babf64617e4694 100644 --- a/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj +++ b/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.Parsing.cs similarity index 100% rename from src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.cs rename to src/libraries/System.Runtime.Numerics/src/System/Numerics/IeeeDecimalNumber.Parsing.cs From bea1d8a2db14707bfb9431a46d0d329418553478 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Fri, 20 Jan 2023 20:32:08 -0600 Subject: [PATCH 30/39] move helper --- .../src/System/Numerics/Decimal32.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index acbc987edc59cc..dd13ba80ede201 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -287,6 +287,12 @@ internal static uint ExtractSignificandFromBits(uint bits) return significand; } + // IEEE 754 specifies NaNs to be propagated + internal static Decimal32 Negate(Decimal32 value) + { + return IsNaN(value) ? value : new Decimal32((ushort)(value._value ^ SignMask)); + } + private static uint StripSign(Decimal32 value) { return value._value & ~SignMask; @@ -1689,11 +1695,5 @@ static bool INumberBase.TryConvertToTruncating(Decimal32 valu /// public static Decimal32 operator +(Decimal32 value) => value; - - // IEEE 754 specifies NaNs to be propagated - internal static Decimal32 Negate(Decimal32 value) - { - return IsNaN(value) ? value : new Decimal32((ushort)(value._value ^ SignMask)); - } } } From 20ae1bf109449177726337e21c1433e232f4630f Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Fri, 20 Jan 2023 20:59:46 -0600 Subject: [PATCH 31/39] Fixed ref file --- .../ref/System.Runtime.Numerics.cs | 57 +++++++++++++------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs index b6b75cafeb3824..c657f026eec516 100644 --- a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs +++ b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs @@ -385,7 +385,6 @@ namespace System.Numerics public readonly partial struct Decimal32 : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable, System.IParsable, System.ISpanFormattable, System.ISpanParsable, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity, System.Numerics.IComparisonOperators, System.Numerics.IDecimalFloatingPointIeee754, System.Numerics.IDecrementOperators, System.Numerics.IDivisionOperators, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions, System.Numerics.IFloatingPoint, System.Numerics.IFloatingPointConstants, System.Numerics.IFloatingPointIeee754, System.Numerics.IHyperbolicFunctions, System.Numerics.IIncrementOperators, System.Numerics.ILogarithmicFunctions, System.Numerics.IMinMaxValue, System.Numerics.IModulusOperators, System.Numerics.IMultiplicativeIdentity, System.Numerics.IMultiplyOperators, System.Numerics.INumber, System.Numerics.INumberBase, System.Numerics.IPowerFunctions, System.Numerics.IRootFunctions, System.Numerics.ISignedNumber, System.Numerics.ISubtractionOperators, System.Numerics.ITrigonometricFunctions, System.Numerics.IUnaryNegationOperators, System.Numerics.IUnaryPlusOperators { private readonly int _dummyPrimitive; - public static System.Numerics.Decimal32 AdditiveIdentity { get { throw null; } } public static System.Numerics.Decimal32 E { get { throw null; } } public static System.Numerics.Decimal32 Epsilon { get { throw null; } } public static System.Numerics.Decimal32 MaxValue { get { throw null; } } @@ -398,7 +397,8 @@ namespace System.Numerics public static System.Numerics.Decimal32 One { get { throw null; } } public static System.Numerics.Decimal32 Pi { get { throw null; } } public static System.Numerics.Decimal32 PositiveInfinity { get { throw null; } } - public static int Radix { get { throw null; } } + static System.Numerics.Decimal32 System.Numerics.IAdditiveIdentity.AdditiveIdentity { get { throw null; } } + static int System.Numerics.INumberBase.Radix { get { throw null; } } public static System.Numerics.Decimal32 Tau { get { throw null; } } public static System.Numerics.Decimal32 Zero { get { throw null; } } public static System.Numerics.Decimal32 Abs(System.Numerics.Decimal32 value) { throw null; } @@ -416,8 +416,11 @@ namespace System.Numerics public static System.Numerics.Decimal32 BitDecrement(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 BitIncrement(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 Cbrt(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Ceiling(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Clamp(System.Numerics.Decimal32 value, System.Numerics.Decimal32 min, System.Numerics.Decimal32 max) { throw null; } public int CompareTo(System.Numerics.Decimal32 other) { throw null; } public int CompareTo(object? obj) { throw null; } + public static System.Numerics.Decimal32 CopySign(System.Numerics.Decimal32 value, System.Numerics.Decimal32 sign) { throw null; } public static System.Numerics.Decimal32 Cos(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 Cosh(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 CosPi(System.Numerics.Decimal32 x) { throw null; } @@ -428,22 +431,18 @@ namespace System.Numerics public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } public static System.Numerics.Decimal32 Exp(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 Exp10(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Exp10M1(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 Exp2(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Exp2M1(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 ExpM1(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Floor(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 FusedMultiplyAdd(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right, System.Numerics.Decimal32 addend) { throw null; } - public int GetExponentByteCount() { throw null; } - public int GetExponentShortestBitLength() { throw null; } public override int GetHashCode() { throw null; } - public int GetSignificandBitLength() { throw null; } - public int GetSignificandByteCount() { throw null; } - public System.TypeCode GetTypeCode() { throw null; } public static System.Numerics.Decimal32 Hypot(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 Ieee754Remainder(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } public static int ILogB(System.Numerics.Decimal32 x) { throw null; } - public static bool IsCanonical(System.Numerics.Decimal32 value) { throw null; } - public static bool IsComplexNumber(System.Numerics.Decimal32 value) { throw null; } public static bool IsEvenInteger(System.Numerics.Decimal32 value) { throw null; } public static bool IsFinite(System.Numerics.Decimal32 value) { throw null; } - public static bool IsImaginaryNumber(System.Numerics.Decimal32 value) { throw null; } public static bool IsInfinity(System.Numerics.Decimal32 value) { throw null; } public static bool IsInteger(System.Numerics.Decimal32 value) { throw null; } public static bool IsNaN(System.Numerics.Decimal32 value) { throw null; } @@ -455,15 +454,21 @@ namespace System.Numerics public static bool IsPositiveInfinity(System.Numerics.Decimal32 value) { throw null; } public static bool IsRealNumber(System.Numerics.Decimal32 value) { throw null; } public static bool IsSubnormal(System.Numerics.Decimal32 value) { throw null; } - public static bool IsZero(System.Numerics.Decimal32 value) { throw null; } public static System.Numerics.Decimal32 Log(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 Log(System.Numerics.Decimal32 x, System.Numerics.Decimal32 newBase) { throw null; } public static System.Numerics.Decimal32 Log10(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Log10P1(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 Log2(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Log2P1(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 LogP1(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Max(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 MaxMagnitude(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 MaxMagnitudeNumber(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } + public static System.Numerics.Decimal32 MaxNumber(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } + public static System.Numerics.Decimal32 Min(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 MinMagnitude(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 MinMagnitudeNumber(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } + public static System.Numerics.Decimal32 MinNumber(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 operator +(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } public static System.Numerics.Decimal32 operator --(System.Numerics.Decimal32 value) { throw null; } public static System.Numerics.Decimal32 operator /(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } @@ -488,16 +493,34 @@ namespace System.Numerics public static System.Numerics.Decimal32 Pow(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 Quantize(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 Quantum(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 ReciprocalEstimate(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 ReciprocalSqrtEstimate(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 RootN(System.Numerics.Decimal32 x, int n) { throw null; } + public static System.Numerics.Decimal32 Round(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Round(System.Numerics.Decimal32 x, int digits) { throw null; } public static System.Numerics.Decimal32 Round(System.Numerics.Decimal32 x, int digits, System.MidpointRounding mode) { throw null; } + public static System.Numerics.Decimal32 Round(System.Numerics.Decimal32 x, System.MidpointRounding mode) { throw null; } public static bool SameQuantum(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 ScaleB(System.Numerics.Decimal32 x, int n) { throw null; } + public static int Sign(System.Numerics.Decimal32 value) { throw null; } public static System.Numerics.Decimal32 Sin(System.Numerics.Decimal32 x) { throw null; } public static (System.Numerics.Decimal32 Sin, System.Numerics.Decimal32 Cos) SinCos(System.Numerics.Decimal32 x) { throw null; } public static (System.Numerics.Decimal32 SinPi, System.Numerics.Decimal32 CosPi) SinCosPi(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 Sinh(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 SinPi(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 Sqrt(System.Numerics.Decimal32 x) { throw null; } + int System.Numerics.IFloatingPoint.GetExponentByteCount() { throw null; } + int System.Numerics.IFloatingPoint.GetExponentShortestBitLength() { throw null; } + int System.Numerics.IFloatingPoint.GetSignificandBitLength() { throw null; } + int System.Numerics.IFloatingPoint.GetSignificandByteCount() { throw null; } + bool System.Numerics.IFloatingPoint.TryWriteExponentBigEndian(System.Span destination, out int bytesWritten) { throw null; } + bool System.Numerics.IFloatingPoint.TryWriteExponentLittleEndian(System.Span destination, out int bytesWritten) { throw null; } + bool System.Numerics.IFloatingPoint.TryWriteSignificandBigEndian(System.Span destination, out int bytesWritten) { throw null; } + bool System.Numerics.IFloatingPoint.TryWriteSignificandLittleEndian(System.Span destination, out int bytesWritten) { throw null; } + static bool System.Numerics.INumberBase.IsCanonical(System.Numerics.Decimal32 value) { throw null; } + static bool System.Numerics.INumberBase.IsComplexNumber(System.Numerics.Decimal32 value) { throw null; } + static bool System.Numerics.INumberBase.IsImaginaryNumber(System.Numerics.Decimal32 value) { throw null; } + static bool System.Numerics.INumberBase.IsZero(System.Numerics.Decimal32 value) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromChecked(TOther value, out System.Numerics.Decimal32 result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromSaturating(TOther value, out System.Numerics.Decimal32 result) { throw null; } static bool System.Numerics.INumberBase.TryConvertFromTruncating(TOther value, out System.Numerics.Decimal32 result) { throw null; } @@ -507,17 +530,17 @@ namespace System.Numerics public static System.Numerics.Decimal32 Tan(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 Tanh(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 TanPi(System.Numerics.Decimal32 x) { throw null; } - public string ToString(string? format, System.IFormatProvider? formatProvider) { throw null; } - public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format, System.IFormatProvider? provider) { throw null; } + public override string ToString() { throw null; } + public string ToString(System.IFormatProvider? provider) { throw null; } + public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] string? format) { throw null; } + public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] string? format, System.IFormatProvider? provider) { throw null; } + public static System.Numerics.Decimal32 Truncate(System.Numerics.Decimal32 x) { throw null; } + public bool TryFormat(System.Span destination, out int charsWritten, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? provider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out System.Numerics.Decimal32 result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out System.Numerics.Decimal32 result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, out System.Numerics.Decimal32 result) { throw null; } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out System.Numerics.Decimal32 result) { throw null; } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.IFormatProvider? provider, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out System.Numerics.Decimal32 result) { throw null; } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.Numerics.Decimal32 result) { throw null; } - public bool TryWriteExponentBigEndian(System.Span destination, out int bytesWritten) { throw null; } - public bool TryWriteExponentLittleEndian(System.Span destination, out int bytesWritten) { throw null; } - public bool TryWriteSignificandBigEndian(System.Span destination, out int bytesWritten) { throw null; } - public bool TryWriteSignificandLittleEndian(System.Span destination, out int bytesWritten) { throw null; } } } From 04607f69b4807196d46d576d627e9d799ba9309a Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Fri, 27 Jan 2023 12:46:52 -0600 Subject: [PATCH 32/39] Add Lerp, comment out Platinum functions and interfaces --- .../src/System/Numerics/Decimal32.cs | 53 ++++++++++--------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index dd13ba80ede201..19e683d06920b1 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -20,7 +20,8 @@ public readonly struct Decimal32 ISpanFormattable, ISpanParsable, IEquatable, - IDecimalFloatingPointIeee754, + IFloatingPoint, + /*IDecimalFloatingPointIeee754,*/ //PLATINUM IMinMaxValue { @@ -685,10 +686,10 @@ public static bool SameQuantum(Decimal32 x, Decimal32 y) public static bool operator !=(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); // - // IExponentialFunctions + // IExponentialFunctions PLATINUM // - /// +/* /// public static Decimal32 Exp(Decimal32 x) => throw new NotImplementedException(); /// @@ -704,7 +705,7 @@ public static bool SameQuantum(Decimal32 x, Decimal32 y) public static Decimal32 Exp10(Decimal32 x) => throw new NotImplementedException(); /// - public static Decimal32 Exp10M1(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Exp10M1(Decimal32 x) => throw new NotImplementedException();*/ // // IFloatingPoint @@ -787,11 +788,11 @@ public static bool SameQuantum(Decimal32 x, Decimal32 y) /// public static Decimal32 PositiveInfinity => new Decimal32(PositiveInfinityBits); // 1.0 / 0.0 - /// - public static Decimal32 Atan2(Decimal32 y, Decimal32 x) => throw new NotImplementedException(); +/* /// + public static Decimal32 Atan2(Decimal32 y, Decimal32 x) => throw new NotImplementedException(); // PLATINUM /// - public static Decimal32 Atan2Pi(Decimal32 y, Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Atan2Pi(Decimal32 y, Decimal32 x) => throw new NotImplementedException();*/ // PLATINUM /// public static Decimal32 BitDecrement(Decimal32 x) => throw new NotImplementedException(); @@ -808,6 +809,9 @@ public static bool SameQuantum(Decimal32 x, Decimal32 y) /// public static int ILogB(Decimal32 x) => throw new NotImplementedException(); + // /// + public static Decimal32 Lerp(Decimal32 value1, Decimal32 value2, Decimal32 amount) => throw new NotImplementedException(); + /// public static Decimal32 ReciprocalEstimate(Decimal32 x) => throw new NotImplementedException(); @@ -818,13 +822,13 @@ public static bool SameQuantum(Decimal32 x, Decimal32 y) public static Decimal32 ScaleB(Decimal32 x, int n) => throw new NotImplementedException(); // /// - // public static Decimal32 Compound(Half x, Decimal32 n) => throw new NotImplementedException(); + // public static Decimal32 Compound(Half x, Decimal32 n) => throw new NotImplementedException(); // PLATINUM // - // IHyperbolicFunctions + // IHyperbolicFunctions PLATINUM // - /// +/* /// public static Decimal32 Acosh(Decimal32 x) => throw new NotImplementedException(); /// @@ -840,7 +844,7 @@ public static bool SameQuantum(Decimal32 x, Decimal32 y) public static Decimal32 Sinh(Decimal32 x) => throw new NotImplementedException(); /// - public static Decimal32 Tanh(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Tanh(Decimal32 x) => throw new NotImplementedException();*/ // // IIncrementOperators @@ -850,10 +854,10 @@ public static bool SameQuantum(Decimal32 x, Decimal32 y) public static Decimal32 operator ++(Decimal32 value) => throw new NotImplementedException(); // - // ILogarithmicFunctions + // ILogarithmicFunctions PLATINUM // - /// +/* /// public static Decimal32 Log(Decimal32 x) => throw new NotImplementedException(); /// @@ -872,7 +876,7 @@ public static bool SameQuantum(Decimal32 x, Decimal32 y) public static Decimal32 Log2P1(Decimal32 x) => throw new NotImplementedException(); /// - public static Decimal32 Log10P1(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 Log10P1(Decimal32 x) => throw new NotImplementedException();*/ // // IMinMaxValue @@ -1600,24 +1604,25 @@ static bool INumberBase.TryConvertToTruncating(Decimal32 valu } // - // IPowerFunctions + // IPowerFunctions // PLATINUM // - /// - public static Decimal32 Pow(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + /*/// + public static Decimal32 Pow(Decimal32 x, Decimal32 y) => throw new NotImplementedException();*/ // // IRootFunctions // - /// - public static Decimal32 Cbrt(Decimal32 x) => throw new NotImplementedException(); + /*/// + public static Decimal32 Cbrt(Decimal32 x) => throw new NotImplementedException(); // PLATINUM /// - public static Decimal32 Hypot(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); + public static Decimal32 Hypot(Decimal32 x, Decimal32 y) => throw new NotImplementedException(); // PLATINUM + /// - public static Decimal32 RootN(Decimal32 x, int n) => throw new NotImplementedException(); + public static Decimal32 RootN(Decimal32 x, int n) => throw new NotImplementedException();*/ // PLATINUM /// public static Decimal32 Sqrt(Decimal32 x) => throw new NotImplementedException(); @@ -1637,10 +1642,10 @@ static bool INumberBase.TryConvertToTruncating(Decimal32 valu public static Decimal32 operator -(Decimal32 left, Decimal32 right) => throw new NotImplementedException(); // - // ITrigonometricFunctions + // ITrigonometricFunctions PLATINUM // - /// +/* /// public static Decimal32 Acos(Decimal32 x) => throw new NotImplementedException(); /// @@ -1680,7 +1685,7 @@ static bool INumberBase.TryConvertToTruncating(Decimal32 valu public static Decimal32 Tan(Decimal32 x) => throw new NotImplementedException(); /// - public static Decimal32 TanPi(Decimal32 x) => throw new NotImplementedException(); + public static Decimal32 TanPi(Decimal32 x) => throw new NotImplementedException();*/ // // IUnaryNegationOperators From b9211501a0cb668b53d30e09d04c1cd75b65203f Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Fri, 27 Jan 2023 13:34:13 -0600 Subject: [PATCH 33/39] Add conversions --- .../src/System/Numerics/Decimal32.cs | 307 +++++++++++++++++- 1 file changed, 293 insertions(+), 14 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index 19e683d06920b1..f71aba88ea3306 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -518,20 +518,299 @@ public bool TryFormat(Span destination, out int charsWritten, [StringSynta // - // Explicit Convert To Decimal32 TODO - // - - // - // Explicit Convert From Decimal32 TODO - // - - // - // Implicit Convert To Decimal32 TODO - // - - // - // Implicit Convert From Decimal32 TODO - // + // Explicit Convert To Decimal32 + // (T -> Decimal32 is lossy) + // + + /// Explicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + [CLSCompliant(false)] + public static explicit operator Decimal32(int value) => throw new NotImplementedException(); + + /// Explicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + [CLSCompliant(false)] + public static explicit operator Decimal32(uint value) => throw new NotImplementedException(); + + + /// Explicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + public static explicit operator Decimal32(nint value) => throw new NotImplementedException(); + + /// Explicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + [CLSCompliant(false)] + public static explicit operator Decimal32(nuint value) => throw new NotImplementedException(); + + /// Explicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + public static explicit operator Decimal32(long value) => throw new NotImplementedException(); + + /// Explicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + [CLSCompliant(false)] + public static explicit operator Decimal32(ulong value) => throw new NotImplementedException(); + + /// Explicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + public static explicit operator Decimal32(Int128 value) => throw new NotImplementedException(); + + /// Explicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + [CLSCompliant(false)] + public static explicit operator Decimal32(UInt128 value) => throw new NotImplementedException(); + + /// Explicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + public static explicit operator Decimal32(Half value) => throw new NotImplementedException(); + + /// Explicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + public static explicit operator Decimal32(float value) => throw new NotImplementedException(); + + /// Explicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + public static explicit operator Decimal32(double value) => throw new NotImplementedException(); + + /// Explicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + public static explicit operator Decimal32(decimal value) => throw new NotImplementedException(); + + // public static explicit operator Decimal32(Decimal64 value) => throw new NotImplementedException(); TODO + // public static explicit operator Decimal32(Decimal128 value) => throw new NotImplementedException(); TODO + + // + // Explicit Convert From Decimal32 + // (Decimal32 -> T is lossy) + // - Includes a "checked" conversion if T cannot represent infinity and NaN + // + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator byte(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + public static explicit operator checked byte(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator sbyte(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + [CLSCompliant(false)] + public static explicit operator checked sbyte(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator char(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + public static explicit operator checked char(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator short(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + public static explicit operator checked short(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator ushort(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + [CLSCompliant(false)] + public static explicit operator checked ushort(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator int(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + public static explicit operator checked int(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator uint(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + [CLSCompliant(false)] + public static explicit operator checked uint(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator nint(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + public static explicit operator checked nint(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator nuint(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + [CLSCompliant(false)] + public static explicit operator checked nuint(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator long(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + public static explicit operator checked long(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator ulong(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + [CLSCompliant(false)] + public static explicit operator checked ulong(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator Int128(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + public static explicit operator checked Int128(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + [CLSCompliant(false)] + public static explicit operator UInt128(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value, throwing an overflow exception for any values that fall outside the representable range. + /// The value to convert. + /// converted to its nearest representable value. + /// is not representable by . + [CLSCompliant(false)] + public static explicit operator checked UInt128(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator Half(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator float(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator double(Decimal32 value) => throw new NotImplementedException(); + + /// Explicitly converts a 32-bit decimal floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator decimal(Decimal32 value) => throw new NotImplementedException(); + + // + // Implicit Convert To Decimal32 + // (T -> Decimal32 is not lossy) + // + + /// Implicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + public static implicit operator Decimal32(byte value) => throw new NotImplementedException(); + + /// Implicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + [CLSCompliant(false)] + public static implicit operator Decimal32(sbyte value) => throw new NotImplementedException(); + + /// Implicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + public static implicit operator Decimal32(char value) => throw new NotImplementedException(); + + /// Implicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + public static implicit operator Decimal32(short value) => throw new NotImplementedException(); + + /// Implicitly converts a value to its nearest representable 32-bit decimal floating-point value. + /// The value to convert. + /// converted to its nearest representable 32-bit decimal floating-point value. + [CLSCompliant(false)] + public static implicit operator Decimal32(ushort value) => throw new NotImplementedException(); + + // + // Implicit Convert From Decimal32 + // (Decimal32 -> T is not lossy) + // + + // public static implicit operator Decimal64(Decimal32 value) => throw new NotImplementedException(); TODO + // public static implicit operator Decimal128(Decimal32 value) => throw new NotImplementedException(); TODO // // IAdditionOperators From d1f3ffeb5450bfd482a9433d77168c3d7daa6c04 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Fri, 27 Jan 2023 13:40:36 -0600 Subject: [PATCH 34/39] Address PR feedback --- .../System.Runtime.Numerics/src/System/Numerics/Decimal32.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index f71aba88ea3306..fbc5033799ffd9 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -10,9 +10,8 @@ namespace System.Numerics { /// - /// An IEEE 754 compliant float16 type. + /// An IEEE 754 compliant decimal32 type. /// - [Serializable] // TODO do we need this? Half doesn't have it, Single does. [StructLayout(LayoutKind.Sequential)] public readonly struct Decimal32 : IComparable, @@ -171,7 +170,7 @@ public readonly struct Decimal32 private const uint PiBits = 0; // TODO private const uint TauBits = 0; // TODO*/ - internal readonly uint _value; // TODO: Single places this at the top, Half places it here. Also, Single has this as private, Half has it as internal. What do we want? + internal readonly uint _value; // // Internal Constructors and Decoders From 35c16651985a26145950fba163a4911b14f9abf8 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Fri, 27 Jan 2023 14:30:25 -0600 Subject: [PATCH 35/39] Move IDecimalFloatingPointIee754.cs, update ref files --- .../System.Private.CoreLib.Shared.projitems | 1 - .../ref/System.Runtime.Numerics.cs | 108 +++++++++++------- .../src/System.Runtime.Numerics.csproj | 1 + .../Numerics/IDecimalFloatingPointIeee754.cs | 10 +- .../System.Runtime/ref/System.Runtime.cs | 6 - 5 files changed, 74 insertions(+), 52 deletions(-) rename src/libraries/{System.Private.CoreLib => System.Runtime.Numerics}/src/System/Numerics/IDecimalFloatingPointIeee754.cs (72%) diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index d1c7a668160a93..d06769d1805656 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -2500,7 +2500,6 @@ - diff --git a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs index c657f026eec516..c1f2fc4acbaecc 100644 --- a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs +++ b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs @@ -382,7 +382,7 @@ namespace System.Numerics public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Numerics.Complex result) { throw null; } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.IFormatProvider? provider, out System.Numerics.Complex result) { throw null; } } - public readonly partial struct Decimal32 : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable, System.IParsable, System.ISpanFormattable, System.ISpanParsable, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity, System.Numerics.IComparisonOperators, System.Numerics.IDecimalFloatingPointIeee754, System.Numerics.IDecrementOperators, System.Numerics.IDivisionOperators, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions, System.Numerics.IFloatingPoint, System.Numerics.IFloatingPointConstants, System.Numerics.IFloatingPointIeee754, System.Numerics.IHyperbolicFunctions, System.Numerics.IIncrementOperators, System.Numerics.ILogarithmicFunctions, System.Numerics.IMinMaxValue, System.Numerics.IModulusOperators, System.Numerics.IMultiplicativeIdentity, System.Numerics.IMultiplyOperators, System.Numerics.INumber, System.Numerics.INumberBase, System.Numerics.IPowerFunctions, System.Numerics.IRootFunctions, System.Numerics.ISignedNumber, System.Numerics.ISubtractionOperators, System.Numerics.ITrigonometricFunctions, System.Numerics.IUnaryNegationOperators, System.Numerics.IUnaryPlusOperators + public readonly partial struct Decimal32 : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable, System.IParsable, System.ISpanFormattable, System.ISpanParsable, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity, System.Numerics.IComparisonOperators, System.Numerics.IDecrementOperators, System.Numerics.IDivisionOperators, System.Numerics.IEqualityOperators, System.Numerics.IFloatingPoint, System.Numerics.IFloatingPointConstants, System.Numerics.IIncrementOperators, System.Numerics.IMinMaxValue, System.Numerics.IModulusOperators, System.Numerics.IMultiplicativeIdentity, System.Numerics.IMultiplyOperators, System.Numerics.INumber, System.Numerics.INumberBase, System.Numerics.ISignedNumber, System.Numerics.ISubtractionOperators, System.Numerics.IUnaryNegationOperators, System.Numerics.IUnaryPlusOperators { private readonly int _dummyPrimitive; public static System.Numerics.Decimal32 E { get { throw null; } } @@ -402,43 +402,21 @@ namespace System.Numerics public static System.Numerics.Decimal32 Tau { get { throw null; } } public static System.Numerics.Decimal32 Zero { get { throw null; } } public static System.Numerics.Decimal32 Abs(System.Numerics.Decimal32 value) { throw null; } - public static System.Numerics.Decimal32 Acos(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Acosh(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 AcosPi(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Asin(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Asinh(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 AsinPi(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Atan(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Atan2(System.Numerics.Decimal32 y, System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Atan2Pi(System.Numerics.Decimal32 y, System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Atanh(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 AtanPi(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 BitDecrement(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 BitIncrement(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Cbrt(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 Ceiling(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 Clamp(System.Numerics.Decimal32 value, System.Numerics.Decimal32 min, System.Numerics.Decimal32 max) { throw null; } public int CompareTo(System.Numerics.Decimal32 other) { throw null; } public int CompareTo(object? obj) { throw null; } public static System.Numerics.Decimal32 CopySign(System.Numerics.Decimal32 value, System.Numerics.Decimal32 sign) { throw null; } - public static System.Numerics.Decimal32 Cos(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Cosh(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 CosPi(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 CreateChecked(TOther value) where TOther : System.Numerics.INumberBase { throw null; } public static System.Numerics.Decimal32 CreateSaturating(TOther value) where TOther : System.Numerics.INumberBase { throw null; } public static System.Numerics.Decimal32 CreateTruncating(TOther value) where TOther : System.Numerics.INumberBase { throw null; } public bool Equals(System.Numerics.Decimal32 other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } - public static System.Numerics.Decimal32 Exp(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Exp10(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Exp10M1(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Exp2(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Exp2M1(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 ExpM1(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 Floor(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 FusedMultiplyAdd(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right, System.Numerics.Decimal32 addend) { throw null; } public override int GetHashCode() { throw null; } - public static System.Numerics.Decimal32 Hypot(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 Ieee754Remainder(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } public static int ILogB(System.Numerics.Decimal32 x) { throw null; } public static bool IsEvenInteger(System.Numerics.Decimal32 value) { throw null; } @@ -454,13 +432,7 @@ namespace System.Numerics public static bool IsPositiveInfinity(System.Numerics.Decimal32 value) { throw null; } public static bool IsRealNumber(System.Numerics.Decimal32 value) { throw null; } public static bool IsSubnormal(System.Numerics.Decimal32 value) { throw null; } - public static System.Numerics.Decimal32 Log(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Log(System.Numerics.Decimal32 x, System.Numerics.Decimal32 newBase) { throw null; } - public static System.Numerics.Decimal32 Log10(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Log10P1(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Log2(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Log2P1(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 LogP1(System.Numerics.Decimal32 x) { throw null; } + public static System.Numerics.Decimal32 Lerp(System.Numerics.Decimal32 value1, System.Numerics.Decimal32 value2, System.Numerics.Decimal32 amount) { throw null; } public static System.Numerics.Decimal32 Max(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 MaxMagnitude(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 MaxMagnitudeNumber(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } @@ -470,11 +442,77 @@ namespace System.Numerics public static System.Numerics.Decimal32 MinMagnitudeNumber(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 MinNumber(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 operator +(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } + public static explicit operator checked byte (System.Numerics.Decimal32 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator checked sbyte (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator checked char (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator checked short (System.Numerics.Decimal32 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator checked ushort (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator checked int (System.Numerics.Decimal32 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator checked uint (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator checked nint (System.Numerics.Decimal32 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator checked nuint (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator checked long (System.Numerics.Decimal32 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator checked ulong (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator checked System.Int128 (System.Numerics.Decimal32 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator checked System.UInt128 (System.Numerics.Decimal32 value) { throw null; } public static System.Numerics.Decimal32 operator --(System.Numerics.Decimal32 value) { throw null; } public static System.Numerics.Decimal32 operator /(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } public static bool operator ==(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } + public static explicit operator System.Numerics.Decimal32 (decimal value) { throw null; } + public static explicit operator System.Numerics.Decimal32 (double value) { throw null; } + public static explicit operator System.Numerics.Decimal32 (System.Half value) { throw null; } + public static explicit operator System.Numerics.Decimal32 (System.Int128 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator System.Numerics.Decimal32 (int value) { throw null; } + public static explicit operator System.Numerics.Decimal32 (long value) { throw null; } + public static explicit operator System.Numerics.Decimal32 (nint value) { throw null; } + public static explicit operator byte (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator char (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator decimal (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator double (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator System.Half (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator System.Int128 (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator short (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator int (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator long (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator nint (System.Numerics.Decimal32 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator sbyte (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator float (System.Numerics.Decimal32 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator System.UInt128 (System.Numerics.Decimal32 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator ushort (System.Numerics.Decimal32 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator uint (System.Numerics.Decimal32 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator ulong (System.Numerics.Decimal32 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator nuint (System.Numerics.Decimal32 value) { throw null; } + public static explicit operator System.Numerics.Decimal32 (float value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator System.Numerics.Decimal32 (System.UInt128 value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator System.Numerics.Decimal32 (uint value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator System.Numerics.Decimal32 (ulong value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator System.Numerics.Decimal32 (nuint value) { throw null; } public static bool operator >(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } public static bool operator >=(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } + public static implicit operator System.Numerics.Decimal32 (byte value) { throw null; } + public static implicit operator System.Numerics.Decimal32 (char value) { throw null; } + public static implicit operator System.Numerics.Decimal32 (short value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static implicit operator System.Numerics.Decimal32 (sbyte value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static implicit operator System.Numerics.Decimal32 (ushort value) { throw null; } public static System.Numerics.Decimal32 operator ++(System.Numerics.Decimal32 value) { throw null; } public static bool operator !=(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } public static bool operator <(System.Numerics.Decimal32 left, System.Numerics.Decimal32 right) { throw null; } @@ -490,12 +528,10 @@ namespace System.Numerics public static System.Numerics.Decimal32 Parse(string s, System.Globalization.NumberStyles style) { throw null; } public static System.Numerics.Decimal32 Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } public static System.Numerics.Decimal32 Parse(string s, System.IFormatProvider? provider) { throw null; } - public static System.Numerics.Decimal32 Pow(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 Quantize(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 Quantum(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 ReciprocalEstimate(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 ReciprocalSqrtEstimate(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 RootN(System.Numerics.Decimal32 x, int n) { throw null; } public static System.Numerics.Decimal32 Round(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 Round(System.Numerics.Decimal32 x, int digits) { throw null; } public static System.Numerics.Decimal32 Round(System.Numerics.Decimal32 x, int digits, System.MidpointRounding mode) { throw null; } @@ -503,11 +539,6 @@ namespace System.Numerics public static bool SameQuantum(System.Numerics.Decimal32 x, System.Numerics.Decimal32 y) { throw null; } public static System.Numerics.Decimal32 ScaleB(System.Numerics.Decimal32 x, int n) { throw null; } public static int Sign(System.Numerics.Decimal32 value) { throw null; } - public static System.Numerics.Decimal32 Sin(System.Numerics.Decimal32 x) { throw null; } - public static (System.Numerics.Decimal32 Sin, System.Numerics.Decimal32 Cos) SinCos(System.Numerics.Decimal32 x) { throw null; } - public static (System.Numerics.Decimal32 SinPi, System.Numerics.Decimal32 CosPi) SinCosPi(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Sinh(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 SinPi(System.Numerics.Decimal32 x) { throw null; } public static System.Numerics.Decimal32 Sqrt(System.Numerics.Decimal32 x) { throw null; } int System.Numerics.IFloatingPoint.GetExponentByteCount() { throw null; } int System.Numerics.IFloatingPoint.GetExponentShortestBitLength() { throw null; } @@ -527,9 +558,6 @@ namespace System.Numerics static bool System.Numerics.INumberBase.TryConvertToChecked(System.Numerics.Decimal32 value, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TOther result) { throw null; } static bool System.Numerics.INumberBase.TryConvertToSaturating(System.Numerics.Decimal32 value, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TOther result) { throw null; } static bool System.Numerics.INumberBase.TryConvertToTruncating(System.Numerics.Decimal32 value, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out TOther result) { throw null; } - public static System.Numerics.Decimal32 Tan(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 Tanh(System.Numerics.Decimal32 x) { throw null; } - public static System.Numerics.Decimal32 TanPi(System.Numerics.Decimal32 x) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] string? format) { throw null; } diff --git a/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj b/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj index babf64617e4694..49d9499a163f0d 100644 --- a/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj +++ b/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj @@ -6,6 +6,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/IDecimalFloatingPointIeee754.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IDecimalFloatingPointIeee754.cs similarity index 72% rename from src/libraries/System.Private.CoreLib/src/System/Numerics/IDecimalFloatingPointIeee754.cs rename to src/libraries/System.Runtime.Numerics/src/System/Numerics/IDecimalFloatingPointIeee754.cs index d5295412b3d19c..81db6742536582 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/IDecimalFloatingPointIeee754.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IDecimalFloatingPointIeee754.cs @@ -5,7 +5,7 @@ namespace System.Numerics { /// Defines an IEEE 754 floating-point type that is represented in a base-10 format. /// The type that implements the interface. - public interface IDecimalFloatingPointIeee754 + internal interface IDecimalFloatingPointIeee754 // TODO make this public eventually : IFloatingPointIeee754 where TSelf : IDecimalFloatingPointIeee754 { @@ -15,10 +15,10 @@ public interface IDecimalFloatingPointIeee754 // 5.5.2 // TODO put these in BitConverter -/* TOther EncodeDecimal(TSelf x); - TSelf DecodeDecimal(TOther x); - TOther EncodeBinary(TSelf x); - TSelf DecodeBinary(TOther x);*/ + /* TOther EncodeDecimal(TSelf x); + TSelf DecodeDecimal(TOther x); + TOther EncodeBinary(TSelf x); + TSelf DecodeBinary(TOther x);*/ // 5.7.3 static abstract bool SameQuantum(TSelf x, TSelf y); diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index bab8a5c1b3208b..848c670d737c8d 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -10309,12 +10309,6 @@ public partial interface IComparisonOperators : System.N static abstract TResult operator <(TSelf left, TOther right); static abstract TResult operator <=(TSelf left, TOther right); } - public partial interface IDecimalFloatingPointIeee754 : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable, System.IParsable, System.ISpanFormattable, System.ISpanParsable, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity, System.Numerics.IComparisonOperators, System.Numerics.IDecrementOperators, System.Numerics.IDivisionOperators, System.Numerics.IEqualityOperators, System.Numerics.IExponentialFunctions, System.Numerics.IFloatingPoint, System.Numerics.IFloatingPointConstants, System.Numerics.IFloatingPointIeee754, System.Numerics.IHyperbolicFunctions, System.Numerics.IIncrementOperators, System.Numerics.ILogarithmicFunctions, System.Numerics.IModulusOperators, System.Numerics.IMultiplicativeIdentity, System.Numerics.IMultiplyOperators, System.Numerics.INumber, System.Numerics.INumberBase, System.Numerics.IPowerFunctions, System.Numerics.IRootFunctions, System.Numerics.ISignedNumber, System.Numerics.ISubtractionOperators, System.Numerics.ITrigonometricFunctions, System.Numerics.IUnaryNegationOperators, System.Numerics.IUnaryPlusOperators where TSelf : System.Numerics.IDecimalFloatingPointIeee754 - { - static abstract TSelf Quantize(TSelf x, TSelf y); - static abstract TSelf Quantum(TSelf x); - static abstract bool SameQuantum(TSelf x, TSelf y); - } public partial interface IDecrementOperators where TSelf : System.Numerics.IDecrementOperators? { static virtual TSelf operator checked --(TSelf value) { throw null; } From 5842c4b7cae9dac23a3a45953a830848cf5d6c34 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Thu, 2 Feb 2023 18:05:40 -0600 Subject: [PATCH 36/39] Add Encode* and Decode* functions --- .../ref/System.Runtime.Numerics.cs | 8 ++++++++ .../src/System/Numerics/Decimal32.cs | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs index c1f2fc4acbaecc..416dbb1bc41474 100644 --- a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs +++ b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs @@ -412,6 +412,14 @@ namespace System.Numerics public static System.Numerics.Decimal32 CreateChecked(TOther value) where TOther : System.Numerics.INumberBase { throw null; } public static System.Numerics.Decimal32 CreateSaturating(TOther value) where TOther : System.Numerics.INumberBase { throw null; } public static System.Numerics.Decimal32 CreateTruncating(TOther value) where TOther : System.Numerics.INumberBase { throw null; } + [System.CLSCompliantAttribute(false)] + public static System.Numerics.Decimal32 DecodeBinary(uint x) { throw null; } + [System.CLSCompliantAttribute(false)] + public static System.Numerics.Decimal32 DecodeDecimal(uint x) { throw null; } + [System.CLSCompliantAttribute(false)] + public static uint EncodeBinary(System.Numerics.Decimal32 x) { throw null; } + [System.CLSCompliantAttribute(false)] + public static uint EncodeDecimal(System.Numerics.Decimal32 x) { throw null; } public bool Equals(System.Numerics.Decimal32 other) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } public static System.Numerics.Decimal32 Floor(System.Numerics.Decimal32 x) { throw null; } diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index fbc5033799ffd9..197b30192a6e67 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -452,6 +452,16 @@ public override int GetHashCode() throw new NotImplementedException(); } + // 5.5.2 of the IEEE Spec + [CLSCompliant(false)] + public static uint EncodeDecimal(Decimal32 x) => throw new NotImplementedException(); + [CLSCompliant(false)] + public static Decimal32 DecodeDecimal(uint x) => throw new NotImplementedException(); + [CLSCompliant(false)] + public static uint EncodeBinary(Decimal32 x) => throw new NotImplementedException(); + [CLSCompliant(false)] + public static Decimal32 DecodeBinary(uint x) => throw new NotImplementedException(); + // // Formatting (IFormattable, ISpanFormattable) // From 8f8d4c2f99e3e25e8e6cc7f67d8bdd0a6c19e4b0 Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Fri, 3 Feb 2023 12:18:55 -0600 Subject: [PATCH 37/39] Small update on interface --- .../src/System/Numerics/IDecimalFloatingPointIeee754.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IDecimalFloatingPointIeee754.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IDecimalFloatingPointIeee754.cs index 81db6742536582..2473438f13a9ff 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/IDecimalFloatingPointIeee754.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/IDecimalFloatingPointIeee754.cs @@ -14,7 +14,7 @@ internal interface IDecimalFloatingPointIeee754 // TODO make this public static abstract TSelf Quantum(TSelf x); // 5.5.2 - // TODO put these in BitConverter + // Maybe expose this on this interface /* TOther EncodeDecimal(TSelf x); TSelf DecodeDecimal(TOther x); TOther EncodeBinary(TSelf x); From 0c3bb82ea1c7a307e2d674155003fcafa92e476b Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Mon, 6 Feb 2023 16:58:56 -0600 Subject: [PATCH 38/39] slight adjustments --- .../src/System/Numerics/Decimal32.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index 197b30192a6e67..06de5929f985d6 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -64,8 +64,8 @@ public readonly struct Decimal32 // If the Classification bits are set to 11XXX, we encode the significand one way. Otherwise, we encode it a different way internal const uint FiniteNumberClassificationMask = 0x6000_0000; - // Finite significands are encoded in two different ways. Encoding type can be selected based on whether or not this bit is set in the decoded significand. - internal const uint SignificandEncodingTypeMask = 0x0080_0000; + // Finite significands are encoded in two different ways, depending on whether the most significant 4 bits of the significand are 0xxx or 100x. Test the MSB to classify. + internal const uint SignificandEncodingTypeMask = 1 << (TrailingSignificandWidth + 3); // Constants representing the private bit-representation for various default values. // See either IEEE-754 2019 section 3.5 or https://en.wikipedia.org/wiki/Decimal32_floating-point_format for a breakdown of the encoding. @@ -141,7 +141,7 @@ public readonly struct Decimal32 // // a. Sign bit. // b. G0 and G1 of the combination field, "11" indicates this version of encoding. - // c. Biased Exponent, which is q + 101. 1011_1111 == 191 == 90 + 101, so this is encoding an q of 90. + // c. Biased Exponent, which is q + 101. 1011_1111 == 191 == 90 + 101, so this is encoding a q of 90. // d. Significand. Section b. indicates an implied prefix of [100]. [100]1_1000_1001_0110_0111_1111 == 9,999,999. // // Encoded value: 9,999,999 x 10^90 @@ -157,7 +157,7 @@ public readonly struct Decimal32 // Section labels: a | b | c // // a. Sign bit. - // b. Biased Exponent, which is q + 101. 0110_0101 == 101 == 0 + 101, so this is encoding an q of 0. + // b. Biased Exponent, which is q + 101. 0110_0101 == 101 == 0 + 101, so this is encoding a q of 0. // c. Significand, set to 1. // // Encoded value: 1 x 10^0 @@ -211,7 +211,7 @@ internal Decimal32(bool sign, sbyte q, uint c) combination |= 0b0001 & (c >> CombinationShift); // combination = (11, biased_exponent, x) } - _value = (uint)(((sign ? 1 : 0) << SignShift) + (combination << CombinationShift) + trailing_sig); + _value = ((sign ? 1U : 0U) << SignShift) + (combination << CombinationShift) + trailing_sig; } internal byte BiasedExponent @@ -290,7 +290,7 @@ internal static uint ExtractSignificandFromBits(uint bits) // IEEE 754 specifies NaNs to be propagated internal static Decimal32 Negate(Decimal32 value) { - return IsNaN(value) ? value : new Decimal32((ushort)(value._value ^ SignMask)); + return IsNaN(value) ? value : new Decimal32(value._value ^ SignMask); } private static uint StripSign(Decimal32 value) From a394ddc3041376834aa0a76af4445687c81a185a Mon Sep 17 00:00:00 2001 From: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Date: Wed, 15 Feb 2023 16:59:06 -0600 Subject: [PATCH 39/39] Adjust constant name --- .../src/System/Numerics/Decimal32.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs index 06de5929f985d6..96631677389049 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Decimal32.cs @@ -62,7 +62,7 @@ public readonly struct Decimal32 internal const uint InfinityMask = 0x7800_0000; // If the Classification bits are set to 11XXX, we encode the significand one way. Otherwise, we encode it a different way - internal const uint FiniteNumberClassificationMask = 0x6000_0000; + internal const uint SpecialEncodingMask = 0x6000_0000; // Finite significands are encoded in two different ways, depending on whether the most significant 4 bits of the significand are 0xxx or 100x. Test the MSB to classify. internal const uint SignificandEncodingTypeMask = 1 << (TrailingSignificandWidth + 3); @@ -253,7 +253,7 @@ internal static byte ExtractBiasedExponentFromBits(uint bits) ushort combination = (ushort)((bits >> CombinationShift) & ShiftedCombinationMask); // Two types of encodings for finite numbers - if ((bits & FiniteNumberClassificationMask) == FiniteNumberClassificationMask) + if ((bits & SpecialEncodingMask) == SpecialEncodingMask) { // G0 and G1 are 11, exponent is stored in G2:G(CombinationWidth - 1) return (byte)(combination >> 1); @@ -272,7 +272,7 @@ internal static uint ExtractSignificandFromBits(uint bits) // Two types of encodings for finite numbers uint significand; - if ((bits & FiniteNumberClassificationMask) == FiniteNumberClassificationMask) + if ((bits & SpecialEncodingMask) == SpecialEncodingMask) { // G0 and G1 are 11, 4 MSBs of significand are 100x, where x is G(CombinationWidth) significand = (uint)(0b1000 | (combination & 0b1));