From 7baf6bf10d2a00e10a8b9b1db645b9bfe628f607 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 22 Apr 2022 11:45:01 -0700 Subject: [PATCH 1/3] Updating BigInteger to implement the generic math interfaces --- .../ref/System.Runtime.Numerics.cs | 43 +- .../src/Resources/Strings.resx | 6 + .../src/System.Runtime.Numerics.csproj | 7 +- .../src/System/Numerics/BigInteger.cs | 1168 ++++++++++++++++- .../src/System/ThrowHelper.cs | 24 + 5 files changed, 1242 insertions(+), 6 deletions(-) create mode 100644 src/libraries/System.Runtime.Numerics/src/System/ThrowHelper.cs 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 8abdc6b581f0f4..75a2ceaf619fee 100644 --- a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs +++ b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs @@ -6,7 +6,7 @@ namespace System.Numerics { - public readonly partial struct BigInteger : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable, System.ISpanFormattable + public readonly partial struct BigInteger : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable, System.IParsable, System.ISpanFormattable, System.ISpanParsable, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity, System.Numerics.IBinaryInteger, System.Numerics.IBinaryNumber, System.Numerics.IBitwiseOperators, System.Numerics.IComparisonOperators, System.Numerics.IDecrementOperators, System.Numerics.IDivisionOperators, System.Numerics.IEqualityOperators, System.Numerics.IIncrementOperators, System.Numerics.IModulusOperators, System.Numerics.IMultiplicativeIdentity, System.Numerics.IMultiplyOperators, System.Numerics.INumber, System.Numerics.INumberBase, System.Numerics.IShiftOperators, System.Numerics.ISignedNumber, System.Numerics.ISubtractionOperators, System.Numerics.IUnaryNegationOperators, System.Numerics.IUnaryPlusOperators { private readonly object _dummy; private readonly int _dummyPrimitive; @@ -29,16 +29,25 @@ namespace System.Numerics public static System.Numerics.BigInteger MinusOne { get { throw null; } } public static System.Numerics.BigInteger One { get { throw null; } } public int Sign { get { throw null; } } + static System.Numerics.BigInteger System.Numerics.IAdditiveIdentity.AdditiveIdentity { get { throw null; } } + static System.Numerics.BigInteger System.Numerics.IMultiplicativeIdentity.MultiplicativeIdentity { get { throw null; } } + static System.Numerics.BigInteger System.Numerics.ISignedNumber.NegativeOne { get { throw null; } } public static System.Numerics.BigInteger Zero { get { throw null; } } public static System.Numerics.BigInteger Abs(System.Numerics.BigInteger value) { throw null; } public static System.Numerics.BigInteger Add(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; } + public static System.Numerics.BigInteger Clamp(System.Numerics.BigInteger value, System.Numerics.BigInteger min, System.Numerics.BigInteger max) { throw null; } public static int Compare(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; } public int CompareTo(long other) { throw null; } public int CompareTo(System.Numerics.BigInteger other) { throw null; } public int CompareTo(object? obj) { throw null; } [System.CLSCompliantAttribute(false)] public int CompareTo(ulong other) { throw null; } + public static System.Numerics.BigInteger CopySign(System.Numerics.BigInteger value, System.Numerics.BigInteger sign) { throw null; } + public static System.Numerics.BigInteger CreateChecked(TOther value) where TOther : System.Numerics.INumber { throw null; } + public static System.Numerics.BigInteger CreateSaturating(TOther value) where TOther : System.Numerics.INumber { throw null; } + public static System.Numerics.BigInteger CreateTruncating(TOther value) where TOther : System.Numerics.INumber { throw null; } public static System.Numerics.BigInteger Divide(System.Numerics.BigInteger dividend, System.Numerics.BigInteger divisor) { throw null; } + public static (System.Numerics.BigInteger Quotient, System.Numerics.BigInteger Remainder) DivRem(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; } public static System.Numerics.BigInteger DivRem(System.Numerics.BigInteger dividend, System.Numerics.BigInteger divisor, out System.Numerics.BigInteger remainder) { throw null; } public bool Equals(long other) { throw null; } public bool Equals(System.Numerics.BigInteger other) { throw null; } @@ -49,11 +58,17 @@ namespace System.Numerics public int GetByteCount(bool isUnsigned = false) { throw null; } public override int GetHashCode() { throw null; } public static System.Numerics.BigInteger GreatestCommonDivisor(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; } + public static bool IsNegative(System.Numerics.BigInteger value) { throw null; } + public static bool IsPow2(System.Numerics.BigInteger value) { throw null; } + public static System.Numerics.BigInteger LeadingZeroCount(System.Numerics.BigInteger value) { throw null; } public static double Log(System.Numerics.BigInteger value) { throw null; } public static double Log(System.Numerics.BigInteger value, double baseValue) { throw null; } public static double Log10(System.Numerics.BigInteger value) { throw null; } + public static System.Numerics.BigInteger Log2(System.Numerics.BigInteger value) { throw null; } public static System.Numerics.BigInteger Max(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; } + public static System.Numerics.BigInteger MaxMagnitude(System.Numerics.BigInteger x, System.Numerics.BigInteger y) { throw null; } public static System.Numerics.BigInteger Min(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; } + public static System.Numerics.BigInteger MinMagnitude(System.Numerics.BigInteger x, System.Numerics.BigInteger y) { throw null; } public static System.Numerics.BigInteger ModPow(System.Numerics.BigInteger value, System.Numerics.BigInteger exponent, System.Numerics.BigInteger modulus) { throw null; } public static System.Numerics.BigInteger Multiply(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; } public static System.Numerics.BigInteger Negate(System.Numerics.BigInteger value) { throw null; } @@ -78,6 +93,7 @@ namespace System.Numerics public static explicit operator short (System.Numerics.BigInteger value) { throw null; } public static explicit operator int (System.Numerics.BigInteger value) { throw null; } public static explicit operator long (System.Numerics.BigInteger value) { throw null; } + public static explicit operator nint (System.Numerics.BigInteger value) { throw null; } [System.CLSCompliantAttribute(false)] public static explicit operator sbyte (System.Numerics.BigInteger value) { throw null; } public static explicit operator float (System.Numerics.BigInteger value) { throw null; } @@ -87,6 +103,8 @@ namespace System.Numerics public static explicit operator uint (System.Numerics.BigInteger value) { throw null; } [System.CLSCompliantAttribute(false)] public static explicit operator ulong (System.Numerics.BigInteger value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static explicit operator nuint (System.Numerics.BigInteger value) { throw null; } public static explicit operator System.Numerics.BigInteger (float value) { throw null; } public static bool operator >(long left, System.Numerics.BigInteger right) { throw null; } public static bool operator >(System.Numerics.BigInteger left, long right) { throw null; } @@ -106,6 +124,7 @@ namespace System.Numerics public static implicit operator System.Numerics.BigInteger (short value) { throw null; } public static implicit operator System.Numerics.BigInteger (int value) { throw null; } public static implicit operator System.Numerics.BigInteger (long value) { throw null; } + public static implicit operator System.Numerics.BigInteger (nint value) { throw null; } [System.CLSCompliantAttribute(false)] public static implicit operator System.Numerics.BigInteger (sbyte value) { throw null; } [System.CLSCompliantAttribute(false)] @@ -114,6 +133,8 @@ namespace System.Numerics public static implicit operator System.Numerics.BigInteger (uint value) { throw null; } [System.CLSCompliantAttribute(false)] public static implicit operator System.Numerics.BigInteger (ulong value) { throw null; } + [System.CLSCompliantAttribute(false)] + public static implicit operator System.Numerics.BigInteger (nuint value) { throw null; } public static System.Numerics.BigInteger operator ++(System.Numerics.BigInteger value) { throw null; } public static bool operator !=(long left, System.Numerics.BigInteger right) { throw null; } public static bool operator !=(System.Numerics.BigInteger left, long right) { throw null; } @@ -144,24 +165,44 @@ namespace System.Numerics public static System.Numerics.BigInteger operator -(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; } public static System.Numerics.BigInteger operator -(System.Numerics.BigInteger value) { throw null; } public static System.Numerics.BigInteger operator +(System.Numerics.BigInteger value) { throw null; } + public static System.Numerics.BigInteger operator >>>(System.Numerics.BigInteger value, int shiftAmount) { throw null; } public static System.Numerics.BigInteger Parse(System.ReadOnlySpan value, System.Globalization.NumberStyles style = System.Globalization.NumberStyles.Integer, System.IFormatProvider? provider = null) { throw null; } + public static System.Numerics.BigInteger Parse(System.ReadOnlySpan s, System.IFormatProvider? provider) { throw null; } public static System.Numerics.BigInteger Parse(string value) { throw null; } public static System.Numerics.BigInteger Parse(string value, System.Globalization.NumberStyles style) { throw null; } public static System.Numerics.BigInteger Parse(string value, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } public static System.Numerics.BigInteger Parse(string value, System.IFormatProvider? provider) { throw null; } + public static System.Numerics.BigInteger PopCount(System.Numerics.BigInteger value) { throw null; } public static System.Numerics.BigInteger Pow(System.Numerics.BigInteger value, int exponent) { throw null; } public static System.Numerics.BigInteger Remainder(System.Numerics.BigInteger dividend, System.Numerics.BigInteger divisor) { throw null; } + 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 System.Numerics.BigInteger System.Numerics.IAdditionOperators.operator checked +(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; } + int System.Numerics.IBinaryInteger.GetByteCount() { throw null; } + long System.Numerics.IBinaryInteger.GetShortestBitLength() { throw null; } + bool System.Numerics.IBinaryInteger.TryWriteLittleEndian(System.Span destination, out int bytesWritten) { throw null; } + static System.Numerics.BigInteger System.Numerics.IDecrementOperators.operator checked --(System.Numerics.BigInteger value) { throw null; } + static System.Numerics.BigInteger System.Numerics.IDivisionOperators.operator checked /(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; } + static System.Numerics.BigInteger System.Numerics.IIncrementOperators.operator checked ++(System.Numerics.BigInteger value) { throw null; } + static System.Numerics.BigInteger System.Numerics.IMultiplyOperators.operator checked *(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; } + static int System.Numerics.INumber.Sign(System.Numerics.BigInteger value) { throw null; } + static System.Numerics.BigInteger System.Numerics.ISubtractionOperators.operator checked -(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; } + static System.Numerics.BigInteger System.Numerics.IUnaryNegationOperators.operator checked -(System.Numerics.BigInteger value) { throw null; } public byte[] ToByteArray() { throw null; } public byte[] ToByteArray(bool isUnsigned = false, bool isBigEndian = false) { 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.BigInteger TrailingZeroCount(System.Numerics.BigInteger value) { throw null; } + public static bool TryCreate(TOther value, out System.Numerics.BigInteger result) where TOther : System.Numerics.INumber { 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 value, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Numerics.BigInteger result) { throw null; } + public static bool TryParse(System.ReadOnlySpan s, System.IFormatProvider? provider, out System.Numerics.BigInteger result) { throw null; } public static bool TryParse(System.ReadOnlySpan value, out System.Numerics.BigInteger result) { throw null; } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? value, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Numerics.BigInteger result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.IFormatProvider? provider, out System.Numerics.BigInteger result) { throw null; } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? value, out System.Numerics.BigInteger result) { throw null; } public bool TryWriteBytes(System.Span destination, out int bytesWritten, bool isUnsigned = false, bool isBigEndian = false) { throw null; } } diff --git a/src/libraries/System.Runtime.Numerics/src/Resources/Strings.resx b/src/libraries/System.Runtime.Numerics/src/Resources/Strings.resx index 25aac5f9c67dc4..89440751d30ea4 100644 --- a/src/libraries/System.Runtime.Numerics/src/Resources/Strings.resx +++ b/src/libraries/System.Runtime.Numerics/src/Resources/Strings.resx @@ -66,9 +66,15 @@ With the AllowHexSpecifier bit set in the enum bit field, the only other valid bits that can be combined into the enum value must be a subset of those in HexNumber. + + '{0}' cannot be greater than {1}. + The parameter must be a BigInteger. + + Non-negative number required. + The value is too large to be represented by this format specifier. 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 3a5359fd2623dd..7634a2ce9d800b 100644 --- a/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj +++ b/src/libraries/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj @@ -1,10 +1,11 @@ - + System.Numerics true $(NetCoreAppCurrent) + @@ -18,13 +19,15 @@ + + + - diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs index cccea3eb2d1a45..710f0cd863b419 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs @@ -2,10 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers; +using System.Buffers.Binary; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace System.Numerics { @@ -15,9 +17,9 @@ public readonly struct BigInteger : ISpanFormattable, IComparable, IComparable, - IEquatable - // IBinaryInteger, - // ISignedNumber + IEquatable, + IBinaryInteger, + ISignedNumber { private const uint kuMaskHighBit = unchecked((uint)int.MinValue); private const int kcbitUint = 32; @@ -1766,6 +1768,31 @@ public static implicit operator BigInteger(ulong value) return new BigInteger(value); } + public static implicit operator BigInteger(nint value) + { + if (Environment.Is64BitProcess) + { + return new BigInteger(value); + } + else + { + return new BigInteger((int)value); + } + } + + [CLSCompliant(false)] + public static implicit operator BigInteger(nuint value) + { + if (Environment.Is64BitProcess) + { + return new BigInteger(value); + } + else + { + return new BigInteger((uint)value); + } + } + public static explicit operator BigInteger(float value) { return new BigInteger(value); @@ -1900,6 +1927,31 @@ public static explicit operator ulong(BigInteger value) return value._bits[0]; } + public static explicit operator nint(BigInteger value) + { + if (Environment.Is64BitProcess) + { + return (nint)(long)value; + } + else + { + return (int)value; + } + } + + [CLSCompliant(false)] + public static explicit operator nuint(BigInteger value) + { + if (Environment.Is64BitProcess) + { + return (nuint)(ulong)value; + } + else + { + return (uint)value; + } + } + public static explicit operator float(BigInteger value) { return (float)((double)value); @@ -2785,5 +2837,1115 @@ private void AssertValid() Debug.Assert(_sign > int.MinValue); } } + + // + // IAdditionOperators + // + + /// + static BigInteger IAdditionOperators.operator checked +(BigInteger left, BigInteger right) => left + right; + + // + // IAdditiveIdentity + // + + /// + static BigInteger IAdditiveIdentity.AdditiveIdentity => Zero; + + // + // IBinaryInteger + // + + /// + public static (BigInteger Quotient, BigInteger Remainder) DivRem(BigInteger left, BigInteger right) + { + BigInteger quotient = DivRem(left, right, out BigInteger remainder); + return (quotient, remainder); + } + + /// + public static BigInteger LeadingZeroCount(BigInteger value) + { + value.AssertValid(); + + if (value._bits is null) + { + return int.LeadingZeroCount(value._sign); + } + + // When the value is positive, we just need to get the lzcnt of the most significant bits + // Otherwise, we're negative and the most significant bit is always set. + + return (value._sign >= 0) ? uint.LeadingZeroCount(value._bits[^1]) : 0; + } + + /// + public static BigInteger PopCount(BigInteger value) + { + value.AssertValid(); + + if (value._bits is null) + { + return int.PopCount(value._sign); + } + + ulong result = 0; + + if (value._sign >= 0) + { + // When the value is positive, we simply need to do a popcount for all bits + + for (int i = 0; i < value._bits.Length; i++) + { + uint part = value._bits[i]; + result += uint.PopCount(part); + } + } + else + { + // When the value is negative, we need to popcount the two's complement representation + // We'll do this "inline" to avoid needing to unnecessarily allocate. + + int i = 0; + uint part; + + do + { + // Simply process bits, adding the carry while the previous value is zero + + part = ~value._bits[i] + 1; + result += uint.PopCount(part); + + i++; + } + while ((part == 0) && (i < value._bits.Length)); + + while (i < value._bits.Length) + { + // Then process the remaining bits only utilizing the one's complement + + part = ~value._bits[i]; + result += uint.PopCount(part); + + i++; + } + } + + return result; + } + + /// + public static BigInteger RotateLeft(BigInteger value, int rotateAmount) + { + value.AssertValid(); + int byteCount = (value._bits is null) ? sizeof(int) : (value._bits.Length * 4); + + // Normalize the rotate amount to drop full rotations + rotateAmount %= (int)(byteCount * 8L); + + if (rotateAmount == 0) + return value; + + if (rotateAmount == int.MinValue) + return RotateRight(RotateRight(value, int.MaxValue), 1); + + if (rotateAmount < 0) + return RotateRight(value, -rotateAmount); + + (int digitShift, int smallShift) = Math.DivRem(rotateAmount, kcbitUint); + + uint[]? xdFromPool = null; + int xl = value._bits?.Length ?? 1; + + Span xd = (xl <= BigIntegerCalculator.StackAllocThreshold) + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : xdFromPool = ArrayPool.Shared.Rent(xl); + xd = xd.Slice(0, xl); + + bool negx = value.GetPartsForBitManipulation(xd); + + int zl = xl; + uint[]? zdFromPool = null; + + Span zd = (zl <= BigIntegerCalculator.StackAllocThreshold) + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : zdFromPool = ArrayPool.Shared.Rent(zl); + zd = zd.Slice(0, zl); + + zd.Clear(); + + if (smallShift == 0) + { + int dstIndex = 0; + int srcIndex = xd.Length - digitShift; + + do + { + // Copy last digitShift elements from xd to the start of zd + zd[dstIndex] = xd[srcIndex]; + + dstIndex++; + srcIndex++; + } + while (srcIndex < xd.Length); + + srcIndex = 0; + + while (dstIndex < zd.Length) + { + // Copy remaining elements from start of xd to end of zd + zd[dstIndex] = xd[srcIndex]; + + dstIndex++; + srcIndex++; + } + } + else + { + int carryShift = kcbitUint - smallShift; + + int dstIndex = 0; + int srcIndex = xd.Length - digitShift; + + uint carry = xd[srcIndex - 1] >> carryShift; + + do + { + uint part = xd[srcIndex]; + + zd[dstIndex] = (part << smallShift) | carry; + carry = part >> carryShift; + + dstIndex++; + srcIndex++; + } + while (srcIndex < xd.Length); + + srcIndex = 0; + + while (dstIndex < zd.Length) + { + uint part = xd[srcIndex]; + + zd[dstIndex] = (part << smallShift) | carry; + carry = part >> carryShift; + + dstIndex++; + srcIndex++; + } + } + + var result = new BigInteger(zd, negx); + + if (xdFromPool != null) + ArrayPool.Shared.Return(xdFromPool); + if (zdFromPool != null) + ArrayPool.Shared.Return(zdFromPool); + + return result; + } + + /// + public static BigInteger RotateRight(BigInteger value, int rotateAmount) + { + value.AssertValid(); + int byteCount = (value._bits is null) ? sizeof(int) : (value._bits.Length * 4); + + // Normalize the rotate amount to drop full rotations + rotateAmount %= (int)(byteCount * 8L); + + if (rotateAmount == 0) + return value; + + if (rotateAmount == int.MinValue) + return RotateLeft(RotateLeft(value, int.MaxValue), 1); + + if (rotateAmount < 0) + return RotateLeft(value, -rotateAmount); + + (int digitShift, int smallShift) = Math.DivRem(rotateAmount, kcbitUint); + + uint[]? xdFromPool = null; + int xl = value._bits?.Length ?? 1; + + Span xd = (xl <= BigIntegerCalculator.StackAllocThreshold) + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : xdFromPool = ArrayPool.Shared.Rent(xl); + xd = xd.Slice(0, xl); + + bool negx = value.GetPartsForBitManipulation(xd); + + int zl = xl; + uint[]? zdFromPool = null; + + Span zd = (zl <= BigIntegerCalculator.StackAllocThreshold) + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : zdFromPool = ArrayPool.Shared.Rent(zl); + zd = zd.Slice(0, zl); + + zd.Clear(); + + if (smallShift == 0) + { + int dstIndex = zd.Length - digitShift; + int srcIndex = 0; + + do + { + // Copy first digitShift elements from xd to the end of zd + zd[dstIndex] = xd[srcIndex]; + + dstIndex++; + srcIndex++; + } + while (dstIndex < zd.Length); + + dstIndex = 0; + + while (srcIndex < xd.Length) + { + // Copy remaining elements from end of xd to start of zd + zd[dstIndex] = xd[srcIndex]; + + dstIndex++; + srcIndex++; + } + } + else + { + int carryShift = kcbitUint - smallShift; + + int dstIndex = zd.Length - digitShift; + int srcIndex = 0; + + uint carry = xd[srcIndex - 1] >> carryShift; + + do + { + uint part = xd[srcIndex]; + + zd[dstIndex] = (part >> smallShift) | carry; + carry = part << carryShift; + + dstIndex++; + srcIndex++; + } + while (dstIndex < zd.Length); + + srcIndex = 0; + + while (srcIndex < xd.Length) + { + uint part = xd[srcIndex]; + + zd[dstIndex] = (part >> smallShift) | carry; + carry = part << carryShift; + + dstIndex++; + srcIndex++; + } + } + + var result = new BigInteger(zd, negx); + + if (xdFromPool != null) + ArrayPool.Shared.Return(xdFromPool); + if (zdFromPool != null) + ArrayPool.Shared.Return(zdFromPool); + + return result; + } + + /// + public static BigInteger TrailingZeroCount(BigInteger value) + { + value.AssertValid(); + + if (value._bits is null) + { + return int.TrailingZeroCount(value._sign); + } + + ulong result = 0; + + if (value._sign >= 0) + { + // When the value is positive, we simply need to do a tzcnt for all bits until we find one set + + uint part = value._bits[0]; + + for (int i = 1; (part == 0) && (i < value._bits.Length); i++) + { + part = value._bits[i]; + result += (sizeof(uint) * 8); + + i++; + } + + result += uint.TrailingZeroCount(part); + } + else + { + // When the value is negative, we need to tzcnt the two's complement representation + // We'll do this "inline" to avoid needing to unnecessarily allocate. + + uint part = ~value._bits[0] + 1; + + for (int i = 1; (part == 0) && (i < value._bits.Length); i++) + { + // Simply process bits, adding the carry while the previous value is zero + + part = ~value._bits[i] + 1; + result += (sizeof(uint) * 8); + + i++; + } + + result += uint.TrailingZeroCount(part); + } + + return result; + } + + /// + long IBinaryInteger.GetShortestBitLength() + { + uint[]? bits = _bits; + + if (bits is null) + { + int value = _sign; + + if (value >= 0) + { + return (sizeof(int) * 8) - int.LeadingZeroCount(value); + } + else + { + return (sizeof(int) * 8) + 1 - int.LeadingZeroCount(~value); + } + } + + long result = (bits.Length - 1) * 4; + + if (_sign >= 0) + { + result += (sizeof(uint) * 8) - uint.LeadingZeroCount(bits[^1]); + } + else + { + result += (sizeof(uint) * 8) + 1 - uint.LeadingZeroCount(~bits[^1]); + } + + return result; + } + + /// + int IBinaryInteger.GetByteCount() + { + uint[]? bits = _bits; + + if (bits is null) + { + return sizeof(int); + } + return bits.Length * 4; + } + + /// + bool IBinaryInteger.TryWriteLittleEndian(Span destination, out int bytesWritten) + { + uint[]? bits = _bits; + int byteCount = (bits is null) ? sizeof(int) : bits.Length * 4; + + if (destination.Length >= byteCount) + { + if (bits is null) + { + int value = BitConverter.IsLittleEndian ? _sign : BinaryPrimitives.ReverseEndianness(_sign); + Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value); + } + else if (_sign >= 0) + { + // When the value is positive, we simply need to copy all bits as little endian + + ref byte address = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < bits.Length; i++) + { + uint part = bits[i]; + + if (!BitConverter.IsLittleEndian) + { + part = BinaryPrimitives.ReverseEndianness(part); + } + + Unsafe.WriteUnaligned(ref address, part); + address = ref Unsafe.Add(ref address, sizeof(uint)); + } + } + else + { + // When the value is negative, we need to copy the two's complement representation + // We'll do this "inline" to avoid needing to unnecessarily allocate. + + ref byte address = ref MemoryMarshal.GetReference(destination); + + int i = 0; + uint part; + + do + { + part = ~bits[i] + 1; + + Unsafe.WriteUnaligned(ref address, part); + address = ref Unsafe.Add(ref address, sizeof(uint)); + + i++; + } + while ((part == 0) && (i < bits.Length)); + + while (i < bits.Length) + { + part = ~bits[i]; + + Unsafe.WriteUnaligned(ref address, part); + address = ref Unsafe.Add(ref address, sizeof(uint)); + + i++; + } + } + + bytesWritten = byteCount; + return true; + } + else + { + bytesWritten = 0; + return false; + } + } + + // + // IBinaryNumber + // + + /// + public static bool IsPow2(BigInteger value) => value.IsPowerOfTwo; + + /// + public static BigInteger Log2(BigInteger value) + { + if (IsNegative(value)) + { + ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException(); + } + + if (value._bits is null) + { + return 31 ^ uint.LeadingZeroCount((uint)(value._sign | 1)); + } + + return ((value._bits.Length * 4) - 1) ^ uint.LeadingZeroCount(value._bits[^1]); + } + + // + // IDecrementOperators + // + + /// + static BigInteger IDecrementOperators.operator checked --(BigInteger value) => --value; + + // + // IDivisionOperators + // + + /// + static BigInteger IDivisionOperators.operator checked /(BigInteger left, BigInteger right) => left / right; + + // + // IIncrementOperators + // + + /// + static BigInteger IIncrementOperators.operator checked ++(BigInteger value) => ++value; + + // + // IMultiplicativeIdentity + // + + /// + static BigInteger IMultiplicativeIdentity.MultiplicativeIdentity => One; + + // + // IMultiplyOperators + // + + /// + static BigInteger IMultiplyOperators.operator checked *(BigInteger left, BigInteger right) => left * right; + + // + // INumber + // + + /// + public static BigInteger Clamp(BigInteger value, BigInteger min, BigInteger max) + { + value.AssertValid(); + min.AssertValid(); + max.AssertValid(); + + if (min > max) + { + ThrowMinMaxException(min, max); + } + + if (value < min) + { + return min; + } + else if (value > max) + { + return max; + } + + return value; + + [DoesNotReturn] + static void ThrowMinMaxException(T min, T max) + { + throw new ArgumentException(SR.Format(SR.Argument_MinMaxValue, min, max)); + } + } + + /// + public static BigInteger CopySign(BigInteger value, BigInteger sign) + { + value.AssertValid(); + sign.AssertValid(); + + int currentSign = value._sign; + + if (value._bits is null) + { + currentSign = (currentSign >= 0) ? 1 : -1; + } + + int targetSign = sign._sign; + + if (sign._bits is null) + { + targetSign = (targetSign >= 0) ? 1 : -1; + } + + return (currentSign == targetSign) ? value : -value; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BigInteger CreateChecked(TOther value) + where TOther : INumber + { + if (typeof(TOther) == typeof(byte)) + { + return (byte)(object)value; + } + else if (typeof(TOther) == typeof(char)) + { + return (char)(object)value; + } + else if (typeof(TOther) == typeof(decimal)) + { + return checked((BigInteger)(decimal)(object)value); + } + else if (typeof(TOther) == typeof(double)) + { + return checked((BigInteger)(double)(object)value); + } + else if (typeof(TOther) == typeof(short)) + { + return (short)(object)value; + } + else if (typeof(TOther) == typeof(int)) + { + return (int)(object)value; + } + else if (typeof(TOther) == typeof(long)) + { + return (long)(object)value; + } + else if (typeof(TOther) == typeof(nint)) + { + return (nint)(object)value; + } + else if (typeof(TOther) == typeof(sbyte)) + { + return (sbyte)(object)value; + } + else if (typeof(TOther) == typeof(float)) + { + return checked((BigInteger)(float)(object)value); + } + else if (typeof(TOther) == typeof(ushort)) + { + return (ushort)(object)value; + } + else if (typeof(TOther) == typeof(uint)) + { + return (uint)(object)value; + } + else if (typeof(TOther) == typeof(ulong)) + { + return (ulong)(object)value; + } + else if (typeof(TOther) == typeof(nuint)) + { + return (nuint)(object)value; + } + else + { + ThrowHelper.ThrowNotSupportedException(); + return default; + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BigInteger CreateSaturating(TOther value) + where TOther : INumber + { + if (typeof(TOther) == typeof(byte)) + { + return (byte)(object)value; + } + else if (typeof(TOther) == typeof(char)) + { + return (char)(object)value; + } + else if (typeof(TOther) == typeof(decimal)) + { + return (BigInteger)(decimal)(object)value; + } + else if (typeof(TOther) == typeof(double)) + { + return (BigInteger)(double)(object)value; + } + else if (typeof(TOther) == typeof(short)) + { + return (short)(object)value; + } + else if (typeof(TOther) == typeof(int)) + { + return (int)(object)value; + } + else if (typeof(TOther) == typeof(long)) + { + return (long)(object)value; + } + else if (typeof(TOther) == typeof(nint)) + { + return (nint)(object)value; + } + else if (typeof(TOther) == typeof(sbyte)) + { + return (sbyte)(object)value; + } + else if (typeof(TOther) == typeof(float)) + { + return (BigInteger)(float)(object)value; + } + else if (typeof(TOther) == typeof(ushort)) + { + return (ushort)(object)value; + } + else if (typeof(TOther) == typeof(uint)) + { + return (uint)(object)value; + } + else if (typeof(TOther) == typeof(ulong)) + { + return (ulong)(object)value; + } + else if (typeof(TOther) == typeof(nuint)) + { + return (nuint)(object)value; + } + else + { + ThrowHelper.ThrowNotSupportedException(); + return default; + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BigInteger CreateTruncating(TOther value) + where TOther : INumber + { + if (typeof(TOther) == typeof(byte)) + { + return (byte)(object)value; + } + else if (typeof(TOther) == typeof(char)) + { + return (char)(object)value; + } + else if (typeof(TOther) == typeof(decimal)) + { + return (BigInteger)(decimal)(object)value; + } + else if (typeof(TOther) == typeof(double)) + { + return (BigInteger)(double)(object)value; + } + else if (typeof(TOther) == typeof(short)) + { + return (short)(object)value; + } + else if (typeof(TOther) == typeof(int)) + { + return (int)(object)value; + } + else if (typeof(TOther) == typeof(long)) + { + return (long)(object)value; + } + else if (typeof(TOther) == typeof(nint)) + { + return (nint)(object)value; + } + else if (typeof(TOther) == typeof(sbyte)) + { + return (sbyte)(object)value; + } + else if (typeof(TOther) == typeof(float)) + { + return (BigInteger)(float)(object)value; + } + else if (typeof(TOther) == typeof(ushort)) + { + return (ushort)(object)value; + } + else if (typeof(TOther) == typeof(uint)) + { + return (uint)(object)value; + } + else if (typeof(TOther) == typeof(ulong)) + { + return (ulong)(object)value; + } + else if (typeof(TOther) == typeof(nuint)) + { + return (nuint)(object)value; + } + else + { + ThrowHelper.ThrowNotSupportedException(); + return default; + } + } + + /// + public static bool IsNegative(BigInteger value) + { + value.AssertValid(); + return value._sign < 0; + } + + /// + public static BigInteger MaxMagnitude(BigInteger x, BigInteger y) + { + x.AssertValid(); + y.AssertValid(); + + BigInteger absX = x; + + if (absX < 0) + { + absX = -absX; + + if (absX < 0) + { + return x; + } + } + + BigInteger absY = y; + + if (absY < 0) + { + absY = -absY; + + if (absY < 0) + { + return y; + } + } + + return (absX >= absY) ? x : y; + } + + /// + public static BigInteger MinMagnitude(BigInteger x, BigInteger y) + { + x.AssertValid(); + y.AssertValid(); + + BigInteger absX = x; + + if (absX < 0) + { + absX = -absX; + + if (absX < 0) + { + return y; + } + } + + BigInteger absY = y; + + if (absY < 0) + { + absY = -absY; + + if (absY < 0) + { + return x; + } + } + + return (absX <= absY) ? x : y; + } + + /// + static int INumber.Sign(BigInteger value) + { + value.AssertValid(); + + if (value._bits is null) + { + return int.Sign(value._sign); + } + + return value._sign; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryCreate(TOther value, out BigInteger result) + where TOther : INumber + { + if (typeof(TOther) == typeof(byte)) + { + result = (byte)(object)value; + return true; + } + else if (typeof(TOther) == typeof(char)) + { + result = (char)(object)value; + return true; + } + else if (typeof(TOther) == typeof(decimal)) + { + result = (BigInteger)(decimal)(object)value; + return true; + } + else if (typeof(TOther) == typeof(double)) + { + var actualValue = (double)(object)value; + + if (!double.IsFinite(actualValue)) + { + result = default; + return false; + } + + result = (BigInteger)actualValue; + return true; + } + else if (typeof(TOther) == typeof(short)) + { + result = (short)(object)value; + return true; + } + else if (typeof(TOther) == typeof(int)) + { + result = (int)(object)value; + return true; + } + else if (typeof(TOther) == typeof(long)) + { + result = (long)(object)value; + return true; + } + else if (typeof(TOther) == typeof(nint)) + { + result = (nint)(object)value; + return true; + } + else if (typeof(TOther) == typeof(sbyte)) + { + result = (sbyte)(object)value; + return true; + } + else if (typeof(TOther) == typeof(float)) + { + var actualValue = (float)(object)value; + + if (!float.IsFinite(actualValue)) + { + result = default; + return false; + } + + result = (BigInteger)actualValue; + return true; + } + else if (typeof(TOther) == typeof(ushort)) + { + result = (ushort)(object)value; + return true; + } + else if (typeof(TOther) == typeof(uint)) + { + result = (uint)(object)value; + return true; + } + else if (typeof(TOther) == typeof(ulong)) + { + result = (ulong)(object)value; + return true; + } + else if (typeof(TOther) == typeof(nuint)) + { + result = (nuint)(object)value; + return true; + } + else + { + ThrowHelper.ThrowNotSupportedException(); + result = default; + return false; + } + } + + // + // IParsable + // + + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out BigInteger result) => TryParse(s, NumberStyles.Integer, provider, out result); + + // + // IShiftOperators + // + + /// + public static BigInteger operator >>>(BigInteger value, int shiftAmount) + { + if (shiftAmount == 0) + return value; + + if (shiftAmount == int.MinValue) + return ((value << int.MaxValue) << 1); + + if (shiftAmount < 0) + return value << -shiftAmount; + + (int digitShift, int smallShift) = Math.DivRem(shiftAmount, kcbitUint); + + BigInteger result; + + uint[]? xdFromPool = null; + int xl = value._bits?.Length ?? 1; + Span xd = (xl <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : xdFromPool = ArrayPool.Shared.Rent(xl)).Slice(0, xl); + + bool negx = value.GetPartsForBitManipulation(xd); + + if (negx) + { + if (shiftAmount >= ((long)kcbitUint * xd.Length)) + { + result = MinusOne; + goto exit; + } + + NumericsHelpers.DangerousMakeTwosComplement(xd); // Mutates xd + } + + uint[]? zdFromPool = null; + int zl = Math.Max(xl - digitShift, 0); + Span zd = ((uint)zl <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : zdFromPool = ArrayPool.Shared.Rent(zl)).Slice(0, zl); + zd.Clear(); + + if (smallShift == 0) + { + for (int i = xd.Length - 1; i >= digitShift; i--) + { + zd[i - digitShift] = xd[i]; + } + } + else + { + int carryShift = kcbitUint - smallShift; + uint carry = 0; + for (int i = xd.Length - 1; i >= digitShift; i--) + { + uint rot = xd[i]; + zd[i - digitShift] = (rot >>> smallShift) | carry; + carry = rot << carryShift; + } + } + + if (negx) + { + NumericsHelpers.DangerousMakeTwosComplement(zd); // Mutates zd + } + + result = new BigInteger(zd, negx); + + if (zdFromPool != null) + ArrayPool.Shared.Return(zdFromPool); + exit: + if (xdFromPool != null) + ArrayPool.Shared.Return(xdFromPool); + + return result; + } + + // + // ISignedNumber + // + + /// + static BigInteger ISignedNumber.NegativeOne => MinusOne; + + // + // ISpanParsable + // + + /// + public static BigInteger Parse(ReadOnlySpan s, IFormatProvider? provider) => Parse(s, NumberStyles.Integer, provider); + + /// + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, out BigInteger result) => TryParse(s, NumberStyles.Integer, provider, out result); + + // + // ISubtractionOperators + // + + /// + static BigInteger ISubtractionOperators.operator checked -(BigInteger left, BigInteger right) => left - right; + + // + // IUnaryNegationOperators + // + + /// + static BigInteger IUnaryNegationOperators.operator checked -(BigInteger value) => -value; } } diff --git a/src/libraries/System.Runtime.Numerics/src/System/ThrowHelper.cs b/src/libraries/System.Runtime.Numerics/src/System/ThrowHelper.cs new file mode 100644 index 00000000000000..541bc574003f48 --- /dev/null +++ b/src/libraries/System.Runtime.Numerics/src/System/ThrowHelper.cs @@ -0,0 +1,24 @@ +// 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; + +namespace System +{ + [StackTraceHidden] + internal static class ThrowHelper + { + [DoesNotReturn] + internal static void ThrowNotSupportedException() + { + throw new NotSupportedException(); + } + + [DoesNotReturn] + internal static void ThrowValueArgumentOutOfRange_NeedNonNegNumException() + { + throw new ArgumentOutOfRangeException("value", SR.ArgumentOutOfRange_NeedNonNegNum); + } + } +} From 590b3073f4cf8860398aa8cd7c73641860874968 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 6 May 2022 07:44:00 -0700 Subject: [PATCH 2/3] Adding generic math tests for BigInteger --- .../src/System/Numerics/BigInteger.cs | 83 +- .../tests/BigIntegerTests.GenericMath.cs | 1553 +++++++++++++++++ .../System.Runtime.Numerics.Tests.csproj | 6 +- 3 files changed, 1625 insertions(+), 17 deletions(-) create mode 100644 src/libraries/System.Runtime.Numerics/tests/BigIntegerTests.GenericMath.cs diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs index 710f0cd863b419..e4edb7101c9c2b 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs @@ -2974,6 +2974,11 @@ public static BigInteger RotateLeft(BigInteger value, int rotateAmount) zd.Clear(); + if (negx) + { + NumericsHelpers.DangerousMakeTwosComplement(xd); + } + if (smallShift == 0) { int dstIndex = 0; @@ -3005,9 +3010,19 @@ public static BigInteger RotateLeft(BigInteger value, int rotateAmount) int carryShift = kcbitUint - smallShift; int dstIndex = 0; - int srcIndex = xd.Length - digitShift; + int srcIndex = 0; - uint carry = xd[srcIndex - 1] >> carryShift; + uint carry = 0; + + if (digitShift == 0) + { + carry = xd[^1] >> carryShift; + } + else + { + srcIndex = xd.Length - digitShift; + carry = xd[srcIndex - 1] >> carryShift; + } do { @@ -3035,6 +3050,15 @@ public static BigInteger RotateLeft(BigInteger value, int rotateAmount) } } + if (negx && (int)zd[^1] < 0) + { + NumericsHelpers.DangerousMakeTwosComplement(zd); + } + else + { + negx = false; + } + var result = new BigInteger(zd, negx); if (xdFromPool != null) @@ -3085,10 +3109,15 @@ public static BigInteger RotateRight(BigInteger value, int rotateAmount) zd.Clear(); + if (negx) + { + NumericsHelpers.DangerousMakeTwosComplement(xd); + } + if (smallShift == 0) { - int dstIndex = zd.Length - digitShift; - int srcIndex = 0; + int dstIndex = 0; + int srcIndex = digitShift; do { @@ -3098,11 +3127,11 @@ public static BigInteger RotateRight(BigInteger value, int rotateAmount) dstIndex++; srcIndex++; } - while (dstIndex < zd.Length); + while (srcIndex < xd.Length); - dstIndex = 0; + srcIndex = 0; - while (srcIndex < xd.Length) + while (dstIndex < zd.Length) { // Copy remaining elements from end of xd to start of zd zd[dstIndex] = xd[srcIndex]; @@ -3115,10 +3144,19 @@ public static BigInteger RotateRight(BigInteger value, int rotateAmount) { int carryShift = kcbitUint - smallShift; - int dstIndex = zd.Length - digitShift; - int srcIndex = 0; + int dstIndex = 0; + int srcIndex = digitShift; - uint carry = xd[srcIndex - 1] >> carryShift; + uint carry = 0; + + if (digitShift == 0) + { + carry = xd[^1] << carryShift; + } + else + { + carry = xd[srcIndex - 1] << carryShift; + } do { @@ -3130,11 +3168,11 @@ public static BigInteger RotateRight(BigInteger value, int rotateAmount) dstIndex++; srcIndex++; } - while (dstIndex < zd.Length); + while (srcIndex < xd.Length); srcIndex = 0; - while (srcIndex < xd.Length) + while (dstIndex < zd.Length) { uint part = xd[srcIndex]; @@ -3146,6 +3184,15 @@ public static BigInteger RotateRight(BigInteger value, int rotateAmount) } } + if (negx && (int)zd[^1] < 0) + { + NumericsHelpers.DangerousMakeTwosComplement(zd); + } + else + { + negx = false; + } + var result = new BigInteger(zd, negx); if (xdFromPool != null) @@ -3226,7 +3273,7 @@ long IBinaryInteger.GetShortestBitLength() } } - long result = (bits.Length - 1) * 4; + long result = (bits.Length - 1) * 32; if (_sign >= 0) { @@ -3346,7 +3393,7 @@ public static BigInteger Log2(BigInteger value) return 31 ^ uint.LeadingZeroCount((uint)(value._sign | 1)); } - return ((value._bits.Length * 4) - 1) ^ uint.LeadingZeroCount(value._bits[^1]); + return ((value._bits.Length * 32) - 1) ^ uint.LeadingZeroCount(value._bits[^1]); } // @@ -3901,9 +3948,13 @@ public static bool TryCreate(TOther value, out BigInteger result) } } - if (negx) + if (negx && (int)zd[^1] < 0) { - NumericsHelpers.DangerousMakeTwosComplement(zd); // Mutates zd + NumericsHelpers.DangerousMakeTwosComplement(zd); + } + else + { + negx = false; } result = new BigInteger(zd, negx); diff --git a/src/libraries/System.Runtime.Numerics/tests/BigIntegerTests.GenericMath.cs b/src/libraries/System.Runtime.Numerics/tests/BigIntegerTests.GenericMath.cs new file mode 100644 index 00000000000000..88d6a915b54419 --- /dev/null +++ b/src/libraries/System.Runtime.Numerics/tests/BigIntegerTests.GenericMath.cs @@ -0,0 +1,1553 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Globalization; +using Xunit; + +namespace System.Numerics.Tests +{ + public class BigIntegerTests_GenericMath + { + internal static readonly BigInteger ByteMaxValue = new BigInteger(byte.MaxValue); + + internal static readonly BigInteger Int16MaxValue = new BigInteger(short.MaxValue); + + internal static readonly BigInteger Int16MaxValuePlusOne = new BigInteger(short.MaxValue + 1U); + + internal static readonly BigInteger Int16MinValue = new BigInteger(short.MinValue); + + internal static readonly BigInteger Int32MaxValue = new BigInteger(int.MaxValue); + + internal static readonly BigInteger Int32MaxValuePlusOne = new BigInteger(int.MaxValue + 1U); + + internal static readonly BigInteger Int32MinValue = new BigInteger(int.MinValue); + + internal static readonly BigInteger Int64MaxValue = new BigInteger(long.MaxValue); + + internal static readonly BigInteger Int64MaxValueMinusOne = new BigInteger(long.MaxValue - 1L); + + internal static readonly BigInteger Int64MaxValuePlusOne = new BigInteger(long.MaxValue + 1UL); + + internal static readonly BigInteger Int64MaxValuePlusTwo = new BigInteger(long.MaxValue + 2UL); + + internal static readonly BigInteger Int64MinValue = new BigInteger(long.MinValue); + + internal static readonly BigInteger Int64MinValueMinusOne = new BigInteger(new byte[] { + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x7F, + 0xFF, 0xFF, 0xFF, 0xFF + }); + + internal static readonly BigInteger Int64MinValuePlusOne = new BigInteger(long.MinValue + 1L); + + internal static readonly BigInteger Int64MinValueTimesTwo = new BigInteger(new byte[] { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + }); + + internal static readonly BigInteger TwoPow64 = new BigInteger(new byte[] { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x01 + }); + + internal static readonly BigInteger NegativeOne = new BigInteger(-1); + + internal static readonly BigInteger NegativeTwo = new BigInteger(-2); + + internal static readonly BigInteger NegativeTwoPow64 = new BigInteger(new byte[] { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xFF + }); + + internal static readonly BigInteger NegativeTwoPow64PlusOne = new BigInteger(new byte[] { + 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xFF + }); + + internal static readonly BigInteger One = new BigInteger(1); + + internal static readonly BigInteger SByteMaxValue = new BigInteger(sbyte.MaxValue); + + internal static readonly BigInteger SByteMaxValuePlusOne = new BigInteger(sbyte.MaxValue + 1U); + + internal static readonly BigInteger SByteMinValue = new BigInteger(sbyte.MinValue); + + internal static readonly BigInteger Two = new BigInteger(2); + + internal static readonly BigInteger UInt16MaxValue = new BigInteger(ushort.MaxValue); + + internal static readonly BigInteger UInt32MaxValue = new BigInteger(uint.MaxValue); + + internal static readonly BigInteger UInt64MaxValue = new BigInteger(ulong.MaxValue); + + internal static readonly BigInteger UInt64MaxValueMinusOne = new BigInteger(ulong.MaxValue - 1); + + internal static readonly BigInteger UInt64MaxValueTimesTwo = new BigInteger(new byte[] { + 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x01 + }, isUnsigned: true); + + internal static readonly BigInteger Zero = new BigInteger(0); + + [Fact] + public static void AdditiveIdentityTest() + { + Assert.Equal(Zero, AdditiveIdentityHelper.AdditiveIdentity); + } + + [Fact] + public static void MultiplicativeIdentityTest() + { + Assert.Equal(One, MultiplicativeIdentityHelper.MultiplicativeIdentity); + } + + [Fact] + public static void NegativeOneTest() + { + Assert.Equal(NegativeOne, SignedNumberHelper.NegativeOne); + } + + [Fact] + public static void OneTest() + { + Assert.Equal(One, NumberBaseHelper.One); + } + + [Fact] + public static void ZeroTest() + { + Assert.Equal(Zero, NumberBaseHelper.Zero); + } + + [Fact] + public static void op_AdditionTest() + { + Assert.Equal(One, AdditionOperatorsHelper.op_Addition(Zero, 1)); + Assert.Equal(Two, AdditionOperatorsHelper.op_Addition(One, 1)); + Assert.Equal(Int64MaxValuePlusOne, AdditionOperatorsHelper.op_Addition(Int64MaxValue, 1)); + + Assert.Equal(Int64MinValuePlusOne, AdditionOperatorsHelper.op_Addition(Int64MinValue, 1)); + Assert.Equal(Zero, AdditionOperatorsHelper.op_Addition(NegativeOne, 1)); + + Assert.Equal(Int64MaxValuePlusTwo, AdditionOperatorsHelper.op_Addition(Int64MaxValuePlusOne, 1)); + Assert.Equal(TwoPow64, AdditionOperatorsHelper.op_Addition(UInt64MaxValue, 1)); + } + + [Fact] + public static void op_CheckedAdditionTest() + { + Assert.Equal(One, AdditionOperatorsHelper.op_CheckedAddition(Zero, 1)); + Assert.Equal(Two, AdditionOperatorsHelper.op_CheckedAddition(One, 1)); + Assert.Equal(Int64MaxValuePlusOne, AdditionOperatorsHelper.op_CheckedAddition(Int64MaxValue, 1)); + + Assert.Equal(Int64MinValuePlusOne, AdditionOperatorsHelper.op_CheckedAddition(Int64MinValue, 1)); + Assert.Equal(Zero, AdditionOperatorsHelper.op_CheckedAddition(NegativeOne, 1)); + + Assert.Equal(Int64MaxValuePlusTwo, AdditionOperatorsHelper.op_CheckedAddition(Int64MaxValuePlusOne, 1)); + Assert.Equal(TwoPow64, AdditionOperatorsHelper.op_CheckedAddition(UInt64MaxValue, 1)); + } + + [Fact] + public static void LeadingZeroCountTest() + { + Assert.Equal((BigInteger)32, BinaryIntegerHelper.LeadingZeroCount(Zero)); + Assert.Equal((BigInteger)31, BinaryIntegerHelper.LeadingZeroCount(One)); + Assert.Equal((BigInteger)1, BinaryIntegerHelper.LeadingZeroCount(Int64MaxValue)); + + Assert.Equal((BigInteger)0, BinaryIntegerHelper.LeadingZeroCount(Int64MinValue)); + Assert.Equal((BigInteger)0, BinaryIntegerHelper.LeadingZeroCount(NegativeOne)); + + Assert.Equal((BigInteger)0, BinaryIntegerHelper.LeadingZeroCount(Int64MaxValuePlusOne)); + Assert.Equal((BigInteger)0, BinaryIntegerHelper.LeadingZeroCount(UInt64MaxValue)); + } + + [Fact] + public static void PopCountTest() + { + Assert.Equal((BigInteger)0, BinaryIntegerHelper.PopCount(Zero)); + Assert.Equal((BigInteger)1, BinaryIntegerHelper.PopCount(One)); + Assert.Equal((BigInteger)63, BinaryIntegerHelper.PopCount(Int64MaxValue)); + + Assert.Equal((BigInteger)1, BinaryIntegerHelper.PopCount(Int64MinValue)); + Assert.Equal((BigInteger)32, BinaryIntegerHelper.PopCount(NegativeOne)); + + Assert.Equal((BigInteger)1, BinaryIntegerHelper.PopCount(Int64MaxValuePlusOne)); + Assert.Equal((BigInteger)64, BinaryIntegerHelper.PopCount(UInt64MaxValue)); + } + + [Fact] + public static void RotateLeftTest() + { + Assert.Equal((BigInteger)0x00000000, BinaryIntegerHelper.RotateLeft(Zero, 1)); + Assert.Equal((BigInteger)0x00000000, BinaryIntegerHelper.RotateLeft(Zero, 32)); + Assert.Equal((BigInteger)0x00000000, BinaryIntegerHelper.RotateLeft(Zero, 33)); + + Assert.Equal((BigInteger)0x00000002, BinaryIntegerHelper.RotateLeft(One, 1)); + Assert.Equal((BigInteger)0x00000001, BinaryIntegerHelper.RotateLeft(One, 32)); + Assert.Equal((BigInteger)0x00000002, BinaryIntegerHelper.RotateLeft(One, 33)); + + Assert.Equal((BigInteger)0xFFFFFFFFFFFFFFFE, BinaryIntegerHelper.RotateLeft(Int64MaxValue, 1)); + Assert.Equal((BigInteger)0xFFFFFFFF7FFFFFFF, BinaryIntegerHelper.RotateLeft(Int64MaxValue, 32)); + Assert.Equal((BigInteger)0xFFFFFFFEFFFFFFFF, BinaryIntegerHelper.RotateLeft(Int64MaxValue, 33)); + + Assert.Equal((BigInteger)0x0000000000000001, BinaryIntegerHelper.RotateLeft(Int64MinValue, 1)); + Assert.Equal((BigInteger)0x0000000080000000, BinaryIntegerHelper.RotateLeft(Int64MinValue, 32)); + Assert.Equal((BigInteger)0x0000000100000000, BinaryIntegerHelper.RotateLeft(Int64MinValue, 33)); + + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFF), BinaryIntegerHelper.RotateLeft(NegativeOne, 1)); + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFF), BinaryIntegerHelper.RotateLeft(NegativeOne, 32)); + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFF), BinaryIntegerHelper.RotateLeft(NegativeOne, 33)); + + Assert.Equal((BigInteger)0x0000000000000001, BinaryIntegerHelper.RotateLeft(Int64MaxValuePlusOne, 1)); + Assert.Equal((BigInteger)0x0000000080000000, BinaryIntegerHelper.RotateLeft(Int64MaxValuePlusOne, 32)); + Assert.Equal((BigInteger)0x0000000100000000, BinaryIntegerHelper.RotateLeft(Int64MaxValuePlusOne, 33)); + + Assert.Equal((BigInteger)0xFFFFFFFFFFFFFFFF, BinaryIntegerHelper.RotateLeft(UInt64MaxValue, 1)); + Assert.Equal((BigInteger)0xFFFFFFFFFFFFFFFF, BinaryIntegerHelper.RotateLeft(UInt64MaxValue, 32)); + Assert.Equal((BigInteger)0xFFFFFFFFFFFFFFFF, BinaryIntegerHelper.RotateLeft(UInt64MaxValue, 33)); + + Assert.Equal((BigInteger)0x00000000, BinaryIntegerHelper.RotateLeft(Zero, -1)); + Assert.Equal((BigInteger)0x00000000, BinaryIntegerHelper.RotateLeft(Zero, -32)); + Assert.Equal((BigInteger)0x00000000, BinaryIntegerHelper.RotateLeft(Zero, -33)); + + Assert.Equal((BigInteger)0x80000000, BinaryIntegerHelper.RotateLeft(One, -1)); + Assert.Equal((BigInteger)0x00000001, BinaryIntegerHelper.RotateLeft(One, -32)); + Assert.Equal((BigInteger)0x80000000, BinaryIntegerHelper.RotateLeft(One, -33)); + + Assert.Equal((BigInteger)0xBFFFFFFFFFFFFFFF, BinaryIntegerHelper.RotateLeft(Int64MaxValue, -1)); + Assert.Equal((BigInteger)0xFFFFFFFF7FFFFFFF, BinaryIntegerHelper.RotateLeft(Int64MaxValue, -32)); + Assert.Equal((BigInteger)0xFFFFFFFFBFFFFFFF, BinaryIntegerHelper.RotateLeft(Int64MaxValue, -33)); + + Assert.Equal((BigInteger)0x4000000000000000, BinaryIntegerHelper.RotateLeft(Int64MinValue, -1)); + Assert.Equal((BigInteger)0x0000000080000000, BinaryIntegerHelper.RotateLeft(Int64MinValue, -32)); + Assert.Equal((BigInteger)0x0000000040000000, BinaryIntegerHelper.RotateLeft(Int64MinValue, -33)); + + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFF), BinaryIntegerHelper.RotateLeft(NegativeOne, -1)); + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFF), BinaryIntegerHelper.RotateLeft(NegativeOne, -32)); + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFF), BinaryIntegerHelper.RotateLeft(NegativeOne, -33)); + + Assert.Equal((BigInteger)0x4000000000000000, BinaryIntegerHelper.RotateLeft(Int64MaxValuePlusOne, -1)); + Assert.Equal((BigInteger)0x0000000080000000, BinaryIntegerHelper.RotateLeft(Int64MaxValuePlusOne, -32)); + Assert.Equal((BigInteger)0x0000000040000000, BinaryIntegerHelper.RotateLeft(Int64MaxValuePlusOne, -33)); + + Assert.Equal((BigInteger)0xFFFFFFFFFFFFFFFF, BinaryIntegerHelper.RotateLeft(UInt64MaxValue, -1)); + Assert.Equal((BigInteger)0xFFFFFFFFFFFFFFFF, BinaryIntegerHelper.RotateLeft(UInt64MaxValue, -32)); + Assert.Equal((BigInteger)0xFFFFFFFFFFFFFFFF, BinaryIntegerHelper.RotateLeft(UInt64MaxValue, -33)); + } + + [Fact] + public static void RotateRightTest() + { + Assert.Equal((BigInteger)0x00000000, BinaryIntegerHelper.RotateRight(Zero, 1)); + Assert.Equal((BigInteger)0x00000000, BinaryIntegerHelper.RotateRight(Zero, 32)); + Assert.Equal((BigInteger)0x00000000, BinaryIntegerHelper.RotateRight(Zero, 33)); + + Assert.Equal((BigInteger)0x80000000, BinaryIntegerHelper.RotateRight(One, 1)); + Assert.Equal((BigInteger)0x00000001, BinaryIntegerHelper.RotateRight(One, 32)); + Assert.Equal((BigInteger)0x80000000, BinaryIntegerHelper.RotateRight(One, 33)); + + Assert.Equal((BigInteger)0xBFFFFFFFFFFFFFFF, BinaryIntegerHelper.RotateRight(Int64MaxValue, 1)); + Assert.Equal((BigInteger)0xFFFFFFFF7FFFFFFF, BinaryIntegerHelper.RotateRight(Int64MaxValue, 32)); + Assert.Equal((BigInteger)0xFFFFFFFFBFFFFFFF, BinaryIntegerHelper.RotateRight(Int64MaxValue, 33)); + + Assert.Equal((BigInteger)0x4000000000000000, BinaryIntegerHelper.RotateRight(Int64MinValue, 1)); + Assert.Equal((BigInteger)0x0000000080000000, BinaryIntegerHelper.RotateRight(Int64MinValue, 32)); + Assert.Equal((BigInteger)0x0000000040000000, BinaryIntegerHelper.RotateRight(Int64MinValue, 33)); + + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFF), BinaryIntegerHelper.RotateRight(NegativeOne, 1)); + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFF), BinaryIntegerHelper.RotateRight(NegativeOne, 32)); + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFF), BinaryIntegerHelper.RotateRight(NegativeOne, 33)); + + Assert.Equal((BigInteger)0x4000000000000000, BinaryIntegerHelper.RotateRight(Int64MaxValuePlusOne, 1)); + Assert.Equal((BigInteger)0x0000000080000000, BinaryIntegerHelper.RotateRight(Int64MaxValuePlusOne, 32)); + Assert.Equal((BigInteger)0x0000000040000000, BinaryIntegerHelper.RotateRight(Int64MaxValuePlusOne, 33)); + + Assert.Equal((BigInteger)0xFFFFFFFFFFFFFFFF, BinaryIntegerHelper.RotateRight(UInt64MaxValue, 1)); + Assert.Equal((BigInteger)0xFFFFFFFFFFFFFFFF, BinaryIntegerHelper.RotateRight(UInt64MaxValue, 32)); + Assert.Equal((BigInteger)0xFFFFFFFFFFFFFFFF, BinaryIntegerHelper.RotateRight(UInt64MaxValue, 33)); + + Assert.Equal((BigInteger)0x00000000, BinaryIntegerHelper.RotateRight(Zero, -1)); + Assert.Equal((BigInteger)0x00000000, BinaryIntegerHelper.RotateRight(Zero, -32)); + Assert.Equal((BigInteger)0x00000000, BinaryIntegerHelper.RotateRight(Zero, -33)); + + Assert.Equal((BigInteger)0x00000002, BinaryIntegerHelper.RotateRight(One, -1)); + Assert.Equal((BigInteger)0x00000001, BinaryIntegerHelper.RotateRight(One, -32)); + Assert.Equal((BigInteger)0x00000002, BinaryIntegerHelper.RotateRight(One, -33)); + + Assert.Equal((BigInteger)0xFFFFFFFFFFFFFFFE, BinaryIntegerHelper.RotateRight(Int64MaxValue, -1)); + Assert.Equal((BigInteger)0xFFFFFFFF7FFFFFFF, BinaryIntegerHelper.RotateRight(Int64MaxValue, -32)); + Assert.Equal((BigInteger)0xFFFFFFFEFFFFFFFF, BinaryIntegerHelper.RotateRight(Int64MaxValue, -33)); + + Assert.Equal((BigInteger)0x0000000000000001, BinaryIntegerHelper.RotateRight(Int64MinValue, -1)); + Assert.Equal((BigInteger)0x0000000080000000, BinaryIntegerHelper.RotateRight(Int64MinValue, -32)); + Assert.Equal((BigInteger)0x0000000100000000, BinaryIntegerHelper.RotateRight(Int64MinValue, -33)); + + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFF), BinaryIntegerHelper.RotateRight(NegativeOne, -1)); + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFF), BinaryIntegerHelper.RotateRight(NegativeOne, -32)); + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFF), BinaryIntegerHelper.RotateRight(NegativeOne, -33)); + + Assert.Equal((BigInteger)0x0000000000000001, BinaryIntegerHelper.RotateRight(Int64MaxValuePlusOne, -1)); + Assert.Equal((BigInteger)0x0000000080000000, BinaryIntegerHelper.RotateRight(Int64MaxValuePlusOne, -32)); + Assert.Equal((BigInteger)0x0000000100000000, BinaryIntegerHelper.RotateRight(Int64MaxValuePlusOne, -33)); + + Assert.Equal((BigInteger)0xFFFFFFFFFFFFFFFF, BinaryIntegerHelper.RotateRight(UInt64MaxValue, -1)); + Assert.Equal((BigInteger)0xFFFFFFFFFFFFFFFF, BinaryIntegerHelper.RotateRight(UInt64MaxValue, -32)); + Assert.Equal((BigInteger)0xFFFFFFFFFFFFFFFF, BinaryIntegerHelper.RotateRight(UInt64MaxValue, -33)); + } + + [Fact] + public static void TrailingZeroCountTest() + { + Assert.Equal((BigInteger)32, BinaryIntegerHelper.TrailingZeroCount(Zero)); + Assert.Equal((BigInteger)0, BinaryIntegerHelper.TrailingZeroCount(One)); + Assert.Equal((BigInteger)0, BinaryIntegerHelper.TrailingZeroCount(Int64MaxValue)); + + Assert.Equal((BigInteger)63, BinaryIntegerHelper.TrailingZeroCount(Int64MinValue)); + Assert.Equal((BigInteger)0, BinaryIntegerHelper.TrailingZeroCount(NegativeOne)); + + Assert.Equal((BigInteger)63, BinaryIntegerHelper.TrailingZeroCount(Int64MaxValuePlusOne)); + Assert.Equal((BigInteger)0, BinaryIntegerHelper.TrailingZeroCount(UInt64MaxValue)); + } + + [Fact] + public static void GetShortestBitLengthTest() + { + Assert.Equal(0x00, BinaryIntegerHelper.GetShortestBitLength(Zero)); + Assert.Equal(0x01, BinaryIntegerHelper.GetShortestBitLength(One)); + Assert.Equal(0x3F, BinaryIntegerHelper.GetShortestBitLength(Int64MaxValue)); + + Assert.Equal(0x40, BinaryIntegerHelper.GetShortestBitLength(Int64MinValue)); + Assert.Equal(0x01, BinaryIntegerHelper.GetShortestBitLength(NegativeOne)); + + Assert.Equal(0x40, BinaryIntegerHelper.GetShortestBitLength(Int64MaxValuePlusOne)); + Assert.Equal(0x40, BinaryIntegerHelper.GetShortestBitLength(UInt64MaxValue)); + } + + [Fact] + public static void IsPow2Test() + { + Assert.False(BinaryNumberHelper.IsPow2(Zero)); + Assert.True(BinaryNumberHelper.IsPow2(One)); + Assert.False(BinaryNumberHelper.IsPow2(Int64MaxValue)); + + Assert.False(BinaryNumberHelper.IsPow2(Int64MinValue)); + Assert.False(BinaryNumberHelper.IsPow2(NegativeOne)); + + Assert.True(BinaryNumberHelper.IsPow2(Int64MaxValuePlusOne)); + Assert.False(BinaryNumberHelper.IsPow2(UInt64MaxValue)); + } + + [Fact] + public static void Log2Test() + { + Assert.Equal((BigInteger)0, BinaryNumberHelper.Log2(Zero)); + Assert.Equal((BigInteger)0, BinaryNumberHelper.Log2(One)); + Assert.Equal((BigInteger)62, BinaryNumberHelper.Log2(Int64MaxValue)); + + Assert.Throws(() => BinaryNumberHelper.Log2(Int64MinValue)); + Assert.Throws(() => BinaryNumberHelper.Log2(NegativeOne)); + + Assert.Equal((BigInteger)63, BinaryNumberHelper.Log2(Int64MaxValuePlusOne)); + Assert.Equal((BigInteger)63, BinaryNumberHelper.Log2(UInt64MaxValue)); + } + + [Fact] + public static void op_BitwiseAndTest() + { + Assert.Equal((BigInteger)0x00000000, BitwiseOperatorsHelper.op_BitwiseAnd(Zero, 1)); + Assert.Equal((BigInteger)0x00000001, BitwiseOperatorsHelper.op_BitwiseAnd(One, 1)); + Assert.Equal((BigInteger)0x00000001, BitwiseOperatorsHelper.op_BitwiseAnd(Int64MaxValue, 1)); + + Assert.Equal((BigInteger)0x00000000, BitwiseOperatorsHelper.op_BitwiseAnd(Int64MinValue, 1)); + Assert.Equal((BigInteger)0x00000001, BitwiseOperatorsHelper.op_BitwiseAnd(NegativeOne, 1)); + + Assert.Equal((BigInteger)0x00000000, BitwiseOperatorsHelper.op_BitwiseAnd(Int64MaxValuePlusOne, 1)); + Assert.Equal((BigInteger)0x00000001, BitwiseOperatorsHelper.op_BitwiseAnd(UInt64MaxValue, 1)); + } + + [Fact] + public static void op_BitwiseOrTest() + { + Assert.Equal((BigInteger)0x00000001, BitwiseOperatorsHelper.op_BitwiseOr(Zero, 1)); + Assert.Equal((BigInteger)0x00000001, BitwiseOperatorsHelper.op_BitwiseOr(One, 1)); + Assert.Equal((BigInteger)0x7FFFFFFFFFFFFFFF, BitwiseOperatorsHelper.op_BitwiseOr(Int64MaxValue, 1)); + + Assert.Equal(unchecked((BigInteger)(long)0x8000000000000001), BitwiseOperatorsHelper.op_BitwiseOr(Int64MinValue, 1)); + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFF), BitwiseOperatorsHelper.op_BitwiseOr(NegativeOne, 1)); + + Assert.Equal((BigInteger)0x8000000000000001, BitwiseOperatorsHelper.op_BitwiseOr(Int64MaxValuePlusOne, 1)); + Assert.Equal((BigInteger)0xFFFFFFFFFFFFFFFF, BitwiseOperatorsHelper.op_BitwiseOr(UInt64MaxValue, 1)); + } + + [Fact] + public static void op_ExclusiveOrTest() + { + Assert.Equal((BigInteger)0x00000001, BitwiseOperatorsHelper.op_ExclusiveOr(Zero, 1)); + Assert.Equal((BigInteger)0x00000000, BitwiseOperatorsHelper.op_ExclusiveOr(One, 1)); + Assert.Equal((BigInteger)0x7FFFFFFFFFFFFFFE, BitwiseOperatorsHelper.op_ExclusiveOr(Int64MaxValue, 1)); + + Assert.Equal(unchecked((BigInteger)(long)0x8000000000000001), BitwiseOperatorsHelper.op_ExclusiveOr(Int64MinValue, 1)); + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFE), BitwiseOperatorsHelper.op_ExclusiveOr(NegativeOne, 1)); + + Assert.Equal((BigInteger)0x8000000000000001, BitwiseOperatorsHelper.op_ExclusiveOr(Int64MaxValuePlusOne, 1)); + Assert.Equal((BigInteger)0xFFFFFFFFFFFFFFFE, BitwiseOperatorsHelper.op_ExclusiveOr(UInt64MaxValue, 1)); + } + + [Fact] + public static void op_OnesComplementTest() + { + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFF), BitwiseOperatorsHelper.op_OnesComplement(Zero)); + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFE), BitwiseOperatorsHelper.op_OnesComplement(One)); + Assert.Equal(unchecked((BigInteger)(long)0x8000000000000000), BitwiseOperatorsHelper.op_OnesComplement(Int64MaxValue)); + + Assert.Equal((BigInteger)0x7FFFFFFFFFFFFFFF, BitwiseOperatorsHelper.op_OnesComplement(Int64MinValue)); + Assert.Equal((BigInteger)0x00000000, BitwiseOperatorsHelper.op_OnesComplement(NegativeOne)); + + Assert.Equal(Int64MinValueMinusOne, BitwiseOperatorsHelper.op_OnesComplement(Int64MaxValuePlusOne)); + + Assert.Equal(NegativeTwoPow64, BitwiseOperatorsHelper.op_OnesComplement(UInt64MaxValue)); + } + + [Fact] + public static void op_LessThanTest() + { + Assert.True(ComparisonOperatorsHelper.op_LessThan(Zero, 1)); + Assert.False(ComparisonOperatorsHelper.op_LessThan(One, 1)); + Assert.False(ComparisonOperatorsHelper.op_LessThan(Int64MaxValue, 1)); + + Assert.True(ComparisonOperatorsHelper.op_LessThan(Int64MinValue, 1)); + Assert.True(ComparisonOperatorsHelper.op_LessThan(NegativeOne, 1)); + + Assert.False(ComparisonOperatorsHelper.op_LessThan(Int64MaxValuePlusOne, 1)); + Assert.False(ComparisonOperatorsHelper.op_LessThan(UInt64MaxValue, 1)); + } + + [Fact] + public static void op_LessThanOrEqualTest() + { + Assert.True(ComparisonOperatorsHelper.op_LessThanOrEqual(Zero, 1)); + Assert.True(ComparisonOperatorsHelper.op_LessThanOrEqual(One, 1)); + Assert.False(ComparisonOperatorsHelper.op_LessThanOrEqual(Int64MaxValue, 1)); + + Assert.True(ComparisonOperatorsHelper.op_LessThanOrEqual(Int64MinValue, 1)); + Assert.True(ComparisonOperatorsHelper.op_LessThanOrEqual(NegativeOne, 1)); + + Assert.False(ComparisonOperatorsHelper.op_LessThanOrEqual(Int64MaxValuePlusOne, 1)); + Assert.False(ComparisonOperatorsHelper.op_LessThanOrEqual(UInt64MaxValue, 1)); + } + + [Fact] + public static void op_GreaterThanTest() + { + Assert.False(ComparisonOperatorsHelper.op_GreaterThan(Zero, 1)); + Assert.False(ComparisonOperatorsHelper.op_GreaterThan(One, 1)); + Assert.True(ComparisonOperatorsHelper.op_GreaterThan(Int64MaxValue, 1)); + + Assert.False(ComparisonOperatorsHelper.op_GreaterThan(Int64MinValue, 1)); + Assert.False(ComparisonOperatorsHelper.op_GreaterThan(NegativeOne, 1)); + + Assert.True(ComparisonOperatorsHelper.op_GreaterThan(Int64MaxValuePlusOne, 1)); + Assert.True(ComparisonOperatorsHelper.op_GreaterThan(UInt64MaxValue, 1)); + } + + [Fact] + public static void op_GreaterThanOrEqualTest() + { + Assert.False(ComparisonOperatorsHelper.op_GreaterThanOrEqual(Zero, 1)); + Assert.True(ComparisonOperatorsHelper.op_GreaterThanOrEqual(One, 1)); + Assert.True(ComparisonOperatorsHelper.op_GreaterThanOrEqual(Int64MaxValue, 1)); + + Assert.False(ComparisonOperatorsHelper.op_GreaterThanOrEqual(Int64MinValue, 1)); + Assert.False(ComparisonOperatorsHelper.op_GreaterThanOrEqual(NegativeOne, 1)); + + Assert.True(ComparisonOperatorsHelper.op_GreaterThanOrEqual(Int64MaxValuePlusOne, 1)); + Assert.True(ComparisonOperatorsHelper.op_GreaterThanOrEqual(UInt64MaxValue, 1)); + } + + [Fact] + public static void op_DecrementTest() + { + Assert.Equal(UInt64MaxValue, DecrementOperatorsHelper.op_Decrement(TwoPow64)); + + Assert.Equal(NegativeOne, DecrementOperatorsHelper.op_Decrement(Zero)); + Assert.Equal(Zero, DecrementOperatorsHelper.op_Decrement(One)); + Assert.Equal(Int64MaxValueMinusOne, DecrementOperatorsHelper.op_Decrement(Int64MaxValue)); + + Assert.Equal(Int64MinValueMinusOne, DecrementOperatorsHelper.op_Decrement(Int64MinValue)); + Assert.Equal(NegativeTwo, DecrementOperatorsHelper.op_Decrement(NegativeOne)); + + Assert.Equal(Int64MaxValue, DecrementOperatorsHelper.op_Decrement(Int64MaxValuePlusOne)); + Assert.Equal(UInt64MaxValueMinusOne, DecrementOperatorsHelper.op_Decrement(UInt64MaxValue)); + } + + [Fact] + public static void op_CheckedDecrementTest() + { + Assert.Equal(UInt64MaxValue, DecrementOperatorsHelper.op_CheckedDecrement(TwoPow64)); + + Assert.Equal(NegativeOne, DecrementOperatorsHelper.op_CheckedDecrement(Zero)); + Assert.Equal(Zero, DecrementOperatorsHelper.op_CheckedDecrement(One)); + Assert.Equal(Int64MaxValueMinusOne, DecrementOperatorsHelper.op_CheckedDecrement(Int64MaxValue)); + + Assert.Equal(Int64MinValueMinusOne, DecrementOperatorsHelper.op_CheckedDecrement(Int64MinValue)); + Assert.Equal(NegativeTwo, DecrementOperatorsHelper.op_CheckedDecrement(NegativeOne)); + + Assert.Equal(Int64MaxValue, DecrementOperatorsHelper.op_CheckedDecrement(Int64MaxValuePlusOne)); + Assert.Equal(UInt64MaxValueMinusOne, DecrementOperatorsHelper.op_CheckedDecrement(UInt64MaxValue)); + } + + [Fact] + public static void op_DivisionTest() + { + Assert.Equal(Zero, DivisionOperatorsHelper.op_Division(Zero, 2)); + Assert.Equal(Zero, DivisionOperatorsHelper.op_Division(One, 2)); + Assert.Equal((BigInteger)0x3FFFFFFFFFFFFFFF, DivisionOperatorsHelper.op_Division(Int64MaxValue, 2)); + + Assert.Equal(unchecked((BigInteger)(long)0xC000000000000000), DivisionOperatorsHelper.op_Division(Int64MinValue, 2)); + Assert.Equal(Zero, DivisionOperatorsHelper.op_Division(NegativeOne, 2)); + + Assert.Equal(unchecked((BigInteger)0x4000000000000000), DivisionOperatorsHelper.op_Division(Int64MaxValuePlusOne, 2)); + Assert.Equal(Int64MaxValue, DivisionOperatorsHelper.op_Division(UInt64MaxValue, 2)); + + Assert.Throws(() => DivisionOperatorsHelper.op_Division(One, 0)); + } + + [Fact] + public static void op_CheckedDivisionTest() + { + Assert.Equal(Zero, DivisionOperatorsHelper.op_CheckedDivision(Zero, 2)); + Assert.Equal(Zero, DivisionOperatorsHelper.op_CheckedDivision(One, 2)); + Assert.Equal((BigInteger)0x3FFFFFFFFFFFFFFF, DivisionOperatorsHelper.op_CheckedDivision(Int64MaxValue, 2)); + + Assert.Equal(unchecked((BigInteger)(long)0xC000000000000000), DivisionOperatorsHelper.op_CheckedDivision(Int64MinValue, 2)); + Assert.Equal(Zero, DivisionOperatorsHelper.op_CheckedDivision(NegativeOne, 2)); + + Assert.Equal(unchecked((BigInteger)0x4000000000000000), DivisionOperatorsHelper.op_CheckedDivision(Int64MaxValuePlusOne, 2)); + Assert.Equal(Int64MaxValue, DivisionOperatorsHelper.op_CheckedDivision(UInt64MaxValue, 2)); + + Assert.Throws(() => DivisionOperatorsHelper.op_CheckedDivision(One, 0)); + } + + [Fact] + public static void op_EqualityTest() + { + Assert.False(EqualityOperatorsHelper.op_Equality(Zero, 1)); + Assert.True(EqualityOperatorsHelper.op_Equality(One, 1)); + Assert.False(EqualityOperatorsHelper.op_Equality(Int64MaxValue, 1)); + + Assert.False(EqualityOperatorsHelper.op_Equality(Int64MinValue, 1)); + Assert.False(EqualityOperatorsHelper.op_Equality(NegativeOne, 1)); + + Assert.False(EqualityOperatorsHelper.op_Equality(Int64MaxValuePlusOne, 1)); + Assert.False(EqualityOperatorsHelper.op_Equality(UInt64MaxValue, 1)); + } + + [Fact] + public static void op_InequalityTest() + { + Assert.True(EqualityOperatorsHelper.op_Inequality(Zero, 1)); + Assert.False(EqualityOperatorsHelper.op_Inequality(One, 1)); + Assert.True(EqualityOperatorsHelper.op_Inequality(Int64MaxValue, 1)); + + Assert.True(EqualityOperatorsHelper.op_Inequality(Int64MinValue, 1)); + Assert.True(EqualityOperatorsHelper.op_Inequality(NegativeOne, 1)); + + Assert.True(EqualityOperatorsHelper.op_Inequality(Int64MaxValuePlusOne, 1)); + Assert.True(EqualityOperatorsHelper.op_Inequality(UInt64MaxValue, 1)); + } + + [Fact] + public static void op_IncrementTest() + { + Assert.Equal(One, IncrementOperatorsHelper.op_Increment(Zero)); + Assert.Equal(Two, IncrementOperatorsHelper.op_Increment(One)); + Assert.Equal(Int64MaxValuePlusOne, IncrementOperatorsHelper.op_Increment(Int64MaxValue)); + + Assert.Equal(Int64MinValuePlusOne, IncrementOperatorsHelper.op_Increment(Int64MinValue)); + Assert.Equal(Zero, IncrementOperatorsHelper.op_Increment(NegativeOne)); + + Assert.Equal(Int64MaxValuePlusTwo, IncrementOperatorsHelper.op_Increment(Int64MaxValuePlusOne)); + Assert.Equal(TwoPow64, IncrementOperatorsHelper.op_Increment(UInt64MaxValue)); + } + + [Fact] + public static void op_CheckedIncrementTest() + { + Assert.Equal(One, IncrementOperatorsHelper.op_CheckedIncrement(Zero)); + Assert.Equal(Two, IncrementOperatorsHelper.op_CheckedIncrement(One)); + Assert.Equal(Int64MaxValuePlusOne, IncrementOperatorsHelper.op_CheckedIncrement(Int64MaxValue)); + + Assert.Equal(Int64MinValuePlusOne, IncrementOperatorsHelper.op_CheckedIncrement(Int64MinValue)); + Assert.Equal(Zero, IncrementOperatorsHelper.op_CheckedIncrement(NegativeOne)); + + Assert.Equal(Int64MaxValuePlusTwo, IncrementOperatorsHelper.op_CheckedIncrement(Int64MaxValuePlusOne)); + Assert.Equal(TwoPow64, IncrementOperatorsHelper.op_CheckedIncrement(UInt64MaxValue)); + } + + [Fact] + public static void op_ModulusTest() + { + Assert.Equal(Zero, ModulusOperatorsHelper.op_Modulus(Zero, 2)); + Assert.Equal(One, ModulusOperatorsHelper.op_Modulus(One, 2)); + Assert.Equal(One, ModulusOperatorsHelper.op_Modulus(Int64MaxValue, 2)); + + Assert.Equal(Zero, ModulusOperatorsHelper.op_Modulus(Int64MinValue, 2)); + Assert.Equal(NegativeOne, ModulusOperatorsHelper.op_Modulus(NegativeOne, 2)); + + Assert.Equal(Zero, ModulusOperatorsHelper.op_Modulus(Int64MaxValuePlusOne, 2)); + Assert.Equal(One, ModulusOperatorsHelper.op_Modulus(UInt64MaxValue, 2)); + + Assert.Throws(() => ModulusOperatorsHelper.op_Modulus(One, 0)); + } + + [Fact] + public static void op_MultiplyTest() + { + Assert.Equal(Zero, MultiplyOperatorsHelper.op_Multiply(Zero, 2)); + Assert.Equal(Two, MultiplyOperatorsHelper.op_Multiply(One, 2)); + Assert.Equal(unchecked((BigInteger)0xFFFFFFFFFFFFFFFE), MultiplyOperatorsHelper.op_Multiply(Int64MaxValue, 2)); + + Assert.Equal(Int64MinValueTimesTwo, MultiplyOperatorsHelper.op_Multiply(Int64MinValue, 2)); + Assert.Equal(NegativeTwo, MultiplyOperatorsHelper.op_Multiply(NegativeOne, 2)); + + Assert.Equal(TwoPow64, MultiplyOperatorsHelper.op_Multiply(Int64MaxValuePlusOne, 2)); + Assert.Equal(UInt64MaxValueTimesTwo, MultiplyOperatorsHelper.op_Multiply(UInt64MaxValue, 2)); + } + + [Fact] + public static void op_CheckedMultiplyTest() + { + Assert.Equal(Zero, MultiplyOperatorsHelper.op_CheckedMultiply(Zero, 2)); + Assert.Equal(Two, MultiplyOperatorsHelper.op_CheckedMultiply(One, 2)); + Assert.Equal(unchecked((BigInteger)0xFFFFFFFFFFFFFFFE), MultiplyOperatorsHelper.op_CheckedMultiply(Int64MaxValue, 2)); + + Assert.Equal(Int64MinValueTimesTwo, MultiplyOperatorsHelper.op_CheckedMultiply(Int64MinValue, 2)); + Assert.Equal(NegativeTwo, MultiplyOperatorsHelper.op_CheckedMultiply(NegativeOne, 2)); + + Assert.Equal(TwoPow64, MultiplyOperatorsHelper.op_CheckedMultiply(Int64MaxValuePlusOne, 2)); + Assert.Equal(UInt64MaxValueTimesTwo, MultiplyOperatorsHelper.op_CheckedMultiply(UInt64MaxValue, 2)); + } + + [Fact] + public static void AbsTest() + { + Assert.Equal(Zero, NumberHelper.Abs(Zero)); + Assert.Equal(One, NumberHelper.Abs(One)); + Assert.Equal(Int64MaxValue, NumberHelper.Abs(Int64MaxValue)); + + Assert.Equal(Int64MaxValuePlusOne, NumberHelper.Abs(Int64MinValue)); + Assert.Equal(One, NumberHelper.Abs(NegativeOne)); + + Assert.Equal(Int64MaxValuePlusOne, NumberHelper.Abs(Int64MaxValuePlusOne)); + Assert.Equal(UInt64MaxValue, NumberHelper.Abs(UInt64MaxValue)); + } + + [Fact] + public static void ClampTest() + { + Assert.Equal((BigInteger)0x00, NumberHelper.Clamp(Zero, unchecked((BigInteger)(int)0xFFFFFFC0), 0x003F)); + Assert.Equal((BigInteger)0x01, NumberHelper.Clamp(One, unchecked((BigInteger)(int)0xFFFFFFC0), 0x003F)); + Assert.Equal((BigInteger)0x3F, NumberHelper.Clamp(Int64MaxValue, unchecked((BigInteger)(int)0xFFFFFFC0), 0x003F)); + + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFC0), NumberHelper.Clamp(Int64MinValue, unchecked((BigInteger)(int)0xFFFFFFC0), 0x003F)); + Assert.Equal(NegativeOne, NumberHelper.Clamp(NegativeOne, unchecked((BigInteger)(int)0xFFFFFFC0), 0x003F)); + + Assert.Equal((BigInteger)0x3F, NumberHelper.Clamp(Int64MaxValuePlusOne, unchecked((BigInteger)(int)0xFFFFFFC0), 0x003F)); + Assert.Equal((BigInteger)0x3F, NumberHelper.Clamp(UInt64MaxValue, unchecked((BigInteger)(int)0xFFFFFFC0), 0x003F)); + } + + [Fact] + public static void CreateCheckedFromByteTest() + { + Assert.Equal(Zero, NumberHelper.CreateChecked(0x00)); + Assert.Equal(One, NumberHelper.CreateChecked(0x01)); + Assert.Equal(SByteMaxValue, NumberHelper.CreateChecked(0x7F)); + Assert.Equal(SByteMaxValuePlusOne, NumberHelper.CreateChecked(0x80)); + Assert.Equal(ByteMaxValue, NumberHelper.CreateChecked(0xFF)); + } + + [Fact] + public static void CreateCheckedFromCharTest() + { + Assert.Equal(Zero, NumberHelper.CreateChecked((char)0x0000)); + Assert.Equal(One, NumberHelper.CreateChecked((char)0x0001)); + Assert.Equal(Int16MaxValue, NumberHelper.CreateChecked((char)0x7FFF)); + Assert.Equal(Int16MaxValuePlusOne, NumberHelper.CreateChecked((char)0x8000)); + Assert.Equal(UInt16MaxValue, NumberHelper.CreateChecked((char)0xFFFF)); + } + + [Fact] + public static void CreateCheckedFromInt16Test() + { + Assert.Equal(Zero, NumberHelper.CreateChecked(0x0000)); + Assert.Equal(One, NumberHelper.CreateChecked(0x0001)); + Assert.Equal(Int16MaxValue, NumberHelper.CreateChecked(0x7FFF)); + Assert.Equal(Int16MinValue, NumberHelper.CreateChecked(unchecked((short)0x8000))); + Assert.Equal(NegativeOne, NumberHelper.CreateChecked(unchecked((short)0xFFFF))); + } + + [Fact] + public static void CreateCheckedFromInt32Test() + { + Assert.Equal(Zero, NumberHelper.CreateChecked(0x00000000)); + Assert.Equal(One, NumberHelper.CreateChecked(0x00000001)); + Assert.Equal(Int32MaxValue, NumberHelper.CreateChecked(0x7FFFFFFF)); + Assert.Equal(Int32MinValue, NumberHelper.CreateChecked(unchecked((int)0x80000000))); + Assert.Equal(NegativeOne, NumberHelper.CreateChecked(unchecked((int)0xFFFFFFFF))); + } + + [Fact] + public static void CreateCheckedFromInt64Test() + { + Assert.Equal(Zero, NumberHelper.CreateChecked(0x00000000)); + Assert.Equal(One, NumberHelper.CreateChecked(0x00000001)); + Assert.Equal(Int64MaxValue, NumberHelper.CreateChecked(0x7FFFFFFFFFFFFFFF)); + Assert.Equal(Int64MinValue, NumberHelper.CreateChecked(unchecked(unchecked((long)0x8000000000000000)))); + Assert.Equal(NegativeOne, NumberHelper.CreateChecked(unchecked(unchecked((long)0xFFFFFFFFFFFFFFFF)))); + } + + [Fact] + public static void CreateCheckedFromIntPtrTest() + { + if (Environment.Is64BitProcess) + { + Assert.Equal(Zero, NumberHelper.CreateChecked(unchecked((nint)0x00000000))); + Assert.Equal(One, NumberHelper.CreateChecked(unchecked((nint)0x00000001))); + Assert.Equal(Int64MaxValue, NumberHelper.CreateChecked(unchecked((nint)0x7FFFFFFFFFFFFFFF))); + Assert.Equal(Int64MinValue, NumberHelper.CreateChecked(unchecked((nint)0x8000000000000000))); + Assert.Equal(NegativeOne, NumberHelper.CreateChecked(unchecked((nint)0xFFFFFFFFFFFFFFFF))); + } + else + { + Assert.Equal(Zero, NumberHelper.CreateChecked((nint)0x00000000)); + Assert.Equal(One, NumberHelper.CreateChecked((nint)0x00000001)); + Assert.Equal(Int32MaxValue, NumberHelper.CreateChecked((nint)0x7FFFFFFF)); + Assert.Equal(Int32MinValue, NumberHelper.CreateChecked(unchecked((nint)0x80000000))); + Assert.Equal(NegativeOne, NumberHelper.CreateChecked(unchecked((nint)0xFFFFFFFF))); + } + } + + [Fact] + public static void CreateCheckedFromSByteTest() + { + Assert.Equal(Zero, NumberHelper.CreateChecked(0x00)); + Assert.Equal(One, NumberHelper.CreateChecked(0x01)); + Assert.Equal(SByteMaxValue, NumberHelper.CreateChecked(0x7F)); + Assert.Equal(SByteMinValue, NumberHelper.CreateChecked(unchecked((sbyte)0x80))); + Assert.Equal(NegativeOne, NumberHelper.CreateChecked(unchecked((sbyte)0xFF))); + } + + [Fact] + public static void CreateCheckedFromUInt16Test() + { + Assert.Equal(Zero, NumberHelper.CreateChecked(0x0000)); + Assert.Equal(One, NumberHelper.CreateChecked(0x0001)); + Assert.Equal(Int16MaxValue, NumberHelper.CreateChecked(0x7FFF)); + Assert.Equal(Int16MaxValuePlusOne, NumberHelper.CreateChecked(0x8000)); + Assert.Equal(UInt16MaxValue, NumberHelper.CreateChecked(0xFFFF)); + } + + [Fact] + public static void CreateCheckedFromUInt32Test() + { + Assert.Equal(Zero, NumberHelper.CreateChecked(0x00000000)); + Assert.Equal(One, NumberHelper.CreateChecked(0x00000001)); + Assert.Equal(Int32MaxValue, NumberHelper.CreateChecked(0x7FFFFFFF)); + Assert.Equal(Int32MaxValuePlusOne, NumberHelper.CreateChecked(0x80000000)); + Assert.Equal(UInt32MaxValue, NumberHelper.CreateChecked(0xFFFFFFFF)); + } + + [Fact] + public static void CreateCheckedFromUInt64Test() + { + Assert.Equal(Zero, NumberHelper.CreateChecked(0x00000000)); + Assert.Equal(One, NumberHelper.CreateChecked(0x00000001)); + Assert.Equal(Int64MaxValue, NumberHelper.CreateChecked(0x7FFFFFFFFFFFFFFF)); + Assert.Equal(Int64MaxValuePlusOne, NumberHelper.CreateChecked(0x8000000000000000)); + Assert.Equal(UInt64MaxValue, NumberHelper.CreateChecked(0xFFFFFFFFFFFFFFFF)); + } + + [Fact] + public static void CreateCheckedFromUIntPtrTest() + { + if (Environment.Is64BitProcess) + { + Assert.Equal(Zero, NumberHelper.CreateChecked(unchecked((nuint)0x00000000))); + Assert.Equal(One, NumberHelper.CreateChecked(unchecked((nuint)0x00000001))); + Assert.Equal(Int64MaxValue, NumberHelper.CreateChecked(unchecked((nuint)0x7FFFFFFFFFFFFFFF))); + Assert.Equal(Int64MaxValuePlusOne, NumberHelper.CreateChecked(unchecked((nuint)0x8000000000000000))); + Assert.Equal(UInt64MaxValue, NumberHelper.CreateChecked(unchecked((nuint)0xFFFFFFFFFFFFFFFF))); + } + else + { + Assert.Equal(Zero, NumberHelper.CreateChecked((nuint)0x00000000)); + Assert.Equal(One, NumberHelper.CreateChecked((nuint)0x00000001)); + Assert.Equal(Int32MaxValue, NumberHelper.CreateChecked((nuint)0x7FFFFFFF)); + Assert.Equal(Int32MaxValuePlusOne, NumberHelper.CreateChecked((nuint)0x80000000)); + Assert.Equal(UInt32MaxValue, NumberHelper.CreateChecked((nuint)0xFFFFFFFF)); + } + } + + [Fact] + public static void CreateSaturatingFromByteTest() + { + Assert.Equal(Zero, NumberHelper.CreateSaturating(0x00)); + Assert.Equal(One, NumberHelper.CreateSaturating(0x01)); + Assert.Equal(SByteMaxValue, NumberHelper.CreateSaturating(0x7F)); + Assert.Equal(SByteMaxValuePlusOne, NumberHelper.CreateSaturating(0x80)); + Assert.Equal(ByteMaxValue, NumberHelper.CreateSaturating(0xFF)); + } + + [Fact] + public static void CreateSaturatingFromCharTest() + { + Assert.Equal(Zero, NumberHelper.CreateSaturating((char)0x0000)); + Assert.Equal(One, NumberHelper.CreateSaturating((char)0x0001)); + Assert.Equal(Int16MaxValue, NumberHelper.CreateSaturating((char)0x7FFF)); + Assert.Equal(Int16MaxValuePlusOne, NumberHelper.CreateSaturating((char)0x8000)); + Assert.Equal(UInt16MaxValue, NumberHelper.CreateSaturating((char)0xFFFF)); + } + + [Fact] + public static void CreateSaturatingFromInt16Test() + { + Assert.Equal(Zero, NumberHelper.CreateSaturating(0x0000)); + Assert.Equal(One, NumberHelper.CreateSaturating(0x0001)); + Assert.Equal(Int16MaxValue, NumberHelper.CreateSaturating(0x7FFF)); + Assert.Equal(Int16MinValue, NumberHelper.CreateSaturating(unchecked((short)0x8000))); + Assert.Equal(NegativeOne, NumberHelper.CreateSaturating(unchecked((short)0xFFFF))); + } + + [Fact] + public static void CreateSaturatingFromInt32Test() + { + Assert.Equal(Zero, NumberHelper.CreateSaturating(0x00000000)); + Assert.Equal(One, NumberHelper.CreateSaturating(0x00000001)); + Assert.Equal(Int32MaxValue, NumberHelper.CreateSaturating(0x7FFFFFFF)); + Assert.Equal(Int32MinValue, NumberHelper.CreateSaturating(unchecked((int)0x80000000))); + Assert.Equal(NegativeOne, NumberHelper.CreateSaturating(unchecked((int)0xFFFFFFFF))); + } + + [Fact] + public static void CreateSaturatingFromInt64Test() + { + Assert.Equal(Zero, NumberHelper.CreateSaturating(0x00000000)); + Assert.Equal(One, NumberHelper.CreateSaturating(0x00000001)); + Assert.Equal(Int64MaxValue, NumberHelper.CreateSaturating(0x7FFFFFFFFFFFFFFF)); + Assert.Equal(Int64MinValue, NumberHelper.CreateSaturating(unchecked((long)0x8000000000000000))); + Assert.Equal(NegativeOne, NumberHelper.CreateSaturating(unchecked((long)0xFFFFFFFFFFFFFFFF))); + } + + [Fact] + public static void CreateSaturatingFromIntPtrTest() + { + if (Environment.Is64BitProcess) + { + Assert.Equal(Zero, NumberHelper.CreateSaturating(unchecked((nint)0x00000000))); + Assert.Equal(One, NumberHelper.CreateSaturating(unchecked((nint)0x00000001))); + Assert.Equal(Int64MaxValue, NumberHelper.CreateSaturating(unchecked((nint)0x7FFFFFFFFFFFFFFF))); + Assert.Equal(Int64MinValue, NumberHelper.CreateSaturating(unchecked((nint)0x8000000000000000))); + Assert.Equal(NegativeOne, NumberHelper.CreateSaturating(unchecked((nint)0xFFFFFFFFFFFFFFFF))); + } + else + { + Assert.Equal(Zero, NumberHelper.CreateSaturating((nint)0x00000000)); + Assert.Equal(One, NumberHelper.CreateSaturating((nint)0x00000001)); + Assert.Equal(Int32MaxValue, NumberHelper.CreateSaturating((nint)0x7FFFFFFF)); + Assert.Equal(Int32MinValue, NumberHelper.CreateSaturating(unchecked((nint)0x80000000))); + Assert.Equal(NegativeOne, NumberHelper.CreateSaturating(unchecked((nint)0xFFFFFFFF))); + } + } + + [Fact] + public static void CreateSaturatingFromSByteTest() + { + Assert.Equal(Zero, NumberHelper.CreateSaturating(0x00)); + Assert.Equal(One, NumberHelper.CreateSaturating(0x01)); + Assert.Equal(SByteMaxValue, NumberHelper.CreateSaturating(0x7F)); + Assert.Equal(SByteMinValue, NumberHelper.CreateSaturating(unchecked((sbyte)0x80))); + Assert.Equal(NegativeOne, NumberHelper.CreateSaturating(unchecked((sbyte)0xFF))); + } + + [Fact] + public static void CreateSaturatingFromUInt16Test() + { + Assert.Equal(Zero, NumberHelper.CreateSaturating(0x0000)); + Assert.Equal(One, NumberHelper.CreateSaturating(0x0001)); + Assert.Equal(Int16MaxValue, NumberHelper.CreateSaturating(0x7FFF)); + Assert.Equal(Int16MaxValuePlusOne, NumberHelper.CreateSaturating(0x8000)); + Assert.Equal(UInt16MaxValue, NumberHelper.CreateSaturating(0xFFFF)); + } + + [Fact] + public static void CreateSaturatingFromUInt32Test() + { + Assert.Equal(Zero, NumberHelper.CreateSaturating(0x00000000)); + Assert.Equal(One, NumberHelper.CreateSaturating(0x00000001)); + Assert.Equal(Int32MaxValue, NumberHelper.CreateSaturating(0x7FFFFFFF)); + Assert.Equal(Int32MaxValuePlusOne, NumberHelper.CreateSaturating(0x80000000)); + Assert.Equal(UInt32MaxValue, NumberHelper.CreateSaturating(0xFFFFFFFF)); + } + + [Fact] + public static void CreateSaturatingFromUInt64Test() + { + Assert.Equal(Zero, NumberHelper.CreateSaturating(0x00000000)); + Assert.Equal(One, NumberHelper.CreateSaturating(0x00000001)); + Assert.Equal(Int64MaxValue, NumberHelper.CreateSaturating(0x7FFFFFFFFFFFFFFF)); + Assert.Equal(Int64MaxValuePlusOne, NumberHelper.CreateSaturating(0x8000000000000000)); + Assert.Equal(UInt64MaxValue, NumberHelper.CreateSaturating(0xFFFFFFFFFFFFFFFF)); + } + + [Fact] + public static void CreateSaturatingFromUIntPtrTest() + { + if (Environment.Is64BitProcess) + { + Assert.Equal(Zero, NumberHelper.CreateSaturating(unchecked((nuint)0x00000000))); + Assert.Equal(One, NumberHelper.CreateSaturating(unchecked((nuint)0x00000001))); + Assert.Equal(Int64MaxValue, NumberHelper.CreateSaturating(unchecked((nuint)0x7FFFFFFFFFFFFFFF))); + Assert.Equal(Int64MaxValuePlusOne, NumberHelper.CreateSaturating(unchecked((nuint)0x8000000000000000))); + Assert.Equal(UInt64MaxValue, NumberHelper.CreateSaturating(unchecked((nuint)0xFFFFFFFFFFFFFFFF))); + } + else + { + Assert.Equal(Zero, NumberHelper.CreateSaturating((nuint)0x00000000)); + Assert.Equal(One, NumberHelper.CreateSaturating((nuint)0x00000001)); + Assert.Equal(Int32MaxValue, NumberHelper.CreateSaturating((nuint)0x7FFFFFFF)); + Assert.Equal(Int32MaxValuePlusOne, NumberHelper.CreateSaturating((nuint)0x80000000)); + Assert.Equal(UInt32MaxValue, NumberHelper.CreateSaturating((nuint)0xFFFFFFFF)); + } + } + + [Fact] + public static void CreateTruncatingFromByteTest() + { + Assert.Equal(Zero, NumberHelper.CreateTruncating(0x00)); + Assert.Equal(One, NumberHelper.CreateTruncating(0x01)); + Assert.Equal(SByteMaxValue, NumberHelper.CreateTruncating(0x7F)); + Assert.Equal(SByteMaxValuePlusOne, NumberHelper.CreateTruncating(0x80)); + Assert.Equal(ByteMaxValue, NumberHelper.CreateTruncating(0xFF)); + } + + [Fact] + public static void CreateTruncatingFromCharTest() + { + Assert.Equal(Zero, NumberHelper.CreateTruncating((char)0x0000)); + Assert.Equal(One, NumberHelper.CreateTruncating((char)0x0001)); + Assert.Equal(Int16MaxValue, NumberHelper.CreateTruncating((char)0x7FFF)); + Assert.Equal(Int16MaxValuePlusOne, NumberHelper.CreateTruncating((char)0x8000)); + Assert.Equal(UInt16MaxValue, NumberHelper.CreateTruncating((char)0xFFFF)); + } + + [Fact] + public static void CreateTruncatingFromInt16Test() + { + Assert.Equal(Zero, NumberHelper.CreateTruncating(0x0000)); + Assert.Equal(One, NumberHelper.CreateTruncating(0x0001)); + Assert.Equal(Int16MaxValue, NumberHelper.CreateTruncating(0x7FFF)); + Assert.Equal(Int16MinValue, NumberHelper.CreateTruncating(unchecked((short)0x8000))); + Assert.Equal(NegativeOne, NumberHelper.CreateTruncating(unchecked((short)0xFFFF))); + } + + [Fact] + public static void CreateTruncatingFromInt32Test() + { + Assert.Equal(Zero, NumberHelper.CreateTruncating(0x00000000)); + Assert.Equal(One, NumberHelper.CreateTruncating(0x00000001)); + Assert.Equal(Int32MaxValue, NumberHelper.CreateTruncating(0x7FFFFFFF)); + Assert.Equal(Int32MinValue, NumberHelper.CreateTruncating(unchecked((int)0x80000000))); + Assert.Equal(NegativeOne, NumberHelper.CreateTruncating(unchecked((int)0xFFFFFFFF))); + } + + [Fact] + public static void CreateTruncatingFromInt64Test() + { + Assert.Equal(Zero, NumberHelper.CreateTruncating(0x00000000)); + Assert.Equal(One, NumberHelper.CreateTruncating(0x00000001)); + Assert.Equal(Int64MaxValue, NumberHelper.CreateTruncating(0x7FFFFFFFFFFFFFFF)); + Assert.Equal(Int64MinValue, NumberHelper.CreateTruncating(unchecked((long)0x8000000000000000))); + Assert.Equal(NegativeOne, NumberHelper.CreateTruncating(unchecked((long)0xFFFFFFFFFFFFFFFF))); + } + + [Fact] + public static void CreateTruncatingFromIntPtrTest() + { + if (Environment.Is64BitProcess) + { + Assert.Equal(Zero, NumberHelper.CreateTruncating(unchecked((nint)0x00000000))); + Assert.Equal(One, NumberHelper.CreateTruncating(unchecked((nint)0x00000001))); + Assert.Equal(Int64MaxValue, NumberHelper.CreateTruncating(unchecked((nint)0x7FFFFFFFFFFFFFFF))); + Assert.Equal(Int64MinValue, NumberHelper.CreateTruncating(unchecked((nint)0x8000000000000000))); + Assert.Equal(NegativeOne, NumberHelper.CreateTruncating(unchecked((nint)0xFFFFFFFFFFFFFFFF))); + } + else + { + Assert.Equal(Zero, NumberHelper.CreateTruncating((nint)0x00000000)); + Assert.Equal(One, NumberHelper.CreateTruncating((nint)0x00000001)); + Assert.Equal(Int32MaxValue, NumberHelper.CreateTruncating((nint)0x7FFFFFFF)); + Assert.Equal(Int32MinValue, NumberHelper.CreateTruncating(unchecked((nint)0x80000000))); + Assert.Equal(NegativeOne, NumberHelper.CreateTruncating(unchecked((nint)0xFFFFFFFF))); + } + } + + [Fact] + public static void CreateTruncatingFromSByteTest() + { + Assert.Equal(Zero, NumberHelper.CreateTruncating(0x00)); + Assert.Equal(One, NumberHelper.CreateTruncating(0x01)); + Assert.Equal(SByteMaxValue, NumberHelper.CreateTruncating(0x7F)); + Assert.Equal(SByteMinValue, NumberHelper.CreateTruncating(unchecked((sbyte)0x80))); + Assert.Equal(NegativeOne, NumberHelper.CreateTruncating(unchecked((sbyte)0xFF))); + } + + [Fact] + public static void CreateTruncatingFromUInt16Test() + { + Assert.Equal(Zero, NumberHelper.CreateTruncating(0x0000)); + Assert.Equal(One, NumberHelper.CreateTruncating(0x0001)); + Assert.Equal(Int16MaxValue, NumberHelper.CreateTruncating(0x7FFF)); + Assert.Equal(Int16MaxValuePlusOne, NumberHelper.CreateTruncating(0x8000)); + Assert.Equal(UInt16MaxValue, NumberHelper.CreateTruncating(0xFFFF)); + } + + [Fact] + public static void CreateTruncatingFromUInt32Test() + { + Assert.Equal(Zero, NumberHelper.CreateTruncating(0x00000000)); + Assert.Equal(One, NumberHelper.CreateTruncating(0x00000001)); + Assert.Equal(Int32MaxValue, NumberHelper.CreateTruncating(0x7FFFFFFF)); + Assert.Equal(Int32MaxValuePlusOne, NumberHelper.CreateTruncating(0x80000000)); + Assert.Equal(UInt32MaxValue, NumberHelper.CreateTruncating(0xFFFFFFFF)); + } + + [Fact] + public static void CreateTruncatingFromUInt64Test() + { + Assert.Equal(Zero, NumberHelper.CreateTruncating(0x00000000)); + Assert.Equal(One, NumberHelper.CreateTruncating(0x00000001)); + Assert.Equal(Int64MaxValue, NumberHelper.CreateTruncating(0x7FFFFFFFFFFFFFFF)); + Assert.Equal(Int64MaxValuePlusOne, NumberHelper.CreateTruncating(0x8000000000000000)); + Assert.Equal(UInt64MaxValue, NumberHelper.CreateTruncating(0xFFFFFFFFFFFFFFFF)); + } + + [Fact] + public static void CreateTruncatingFromUIntPtrTest() + { + if (Environment.Is64BitProcess) + { + Assert.Equal(Zero, NumberHelper.CreateTruncating(unchecked((nuint)0x00000000))); + Assert.Equal(One, NumberHelper.CreateTruncating(unchecked((nuint)0x00000001))); + Assert.Equal(Int64MaxValue, NumberHelper.CreateTruncating(unchecked((nuint)0x7FFFFFFFFFFFFFFF))); + Assert.Equal(Int64MaxValuePlusOne, NumberHelper.CreateTruncating(unchecked((nuint)0x8000000000000000))); + Assert.Equal(UInt64MaxValue, NumberHelper.CreateTruncating(unchecked((nuint)0xFFFFFFFFFFFFFFFF))); + } + else + { + Assert.Equal(Zero, NumberHelper.CreateTruncating((nuint)0x00000000)); + Assert.Equal(One, NumberHelper.CreateTruncating((nuint)0x00000001)); + Assert.Equal(Int32MaxValue, NumberHelper.CreateTruncating((nuint)0x7FFFFFFF)); + Assert.Equal(Int32MaxValuePlusOne, NumberHelper.CreateTruncating((nuint)0x80000000)); + Assert.Equal(UInt32MaxValue, NumberHelper.CreateTruncating((nuint)0xFFFFFFFF)); + } + } + + [Fact] + public static void DivRemTest() + { + Assert.Equal((Zero, Zero), BinaryIntegerHelper.DivRem(Zero, 2)); + Assert.Equal((Zero, One), BinaryIntegerHelper.DivRem(One, 2)); + Assert.Equal(((BigInteger)0x3FFFFFFFFFFFFFFF, One), BinaryIntegerHelper.DivRem(Int64MaxValue, 2)); + + Assert.Equal((unchecked((BigInteger)(long)0xC000000000000000), Zero), BinaryIntegerHelper.DivRem(Int64MinValue, 2)); + Assert.Equal((Zero, NegativeOne), BinaryIntegerHelper.DivRem(NegativeOne, 2)); + + Assert.Equal((unchecked((BigInteger)0x4000000000000000), Zero), BinaryIntegerHelper.DivRem(Int64MaxValuePlusOne, 2)); + Assert.Equal((Int64MaxValue, One), BinaryIntegerHelper.DivRem(UInt64MaxValue, 2)); + } + + [Fact] + public static void MaxTest() + { + Assert.Equal(One, NumberHelper.Max(Zero, 1)); + Assert.Equal(One, NumberHelper.Max(One, 1)); + Assert.Equal(Int64MaxValue, NumberHelper.Max(Int64MaxValue, 1)); + + Assert.Equal(One, NumberHelper.Max(Int64MinValue, 1)); + Assert.Equal(One, NumberHelper.Max(NegativeOne, 1)); + + Assert.Equal(Int64MaxValuePlusOne, NumberHelper.Max(Int64MaxValuePlusOne, 1)); + Assert.Equal(UInt64MaxValue, NumberHelper.Max(UInt64MaxValue, 1)); + } + + [Fact] + public static void MinTest() + { + Assert.Equal(Zero, NumberHelper.Min(Zero, 1)); + Assert.Equal(One, NumberHelper.Min(One, 1)); + Assert.Equal(One, NumberHelper.Min(Int64MaxValue, 1)); + + Assert.Equal(Int64MinValue, NumberHelper.Min(Int64MinValue, 1)); + Assert.Equal(NegativeOne, NumberHelper.Min(NegativeOne, 1)); + + Assert.Equal(One, NumberHelper.Min(Int64MaxValuePlusOne, 1)); + Assert.Equal(One, NumberHelper.Min(UInt64MaxValue, 1)); + } + + [Fact] + public static void SignTest() + { + Assert.Equal(0, NumberHelper.Sign(Zero)); + Assert.Equal(1, NumberHelper.Sign(One)); + Assert.Equal(1, NumberHelper.Sign(Int64MaxValue)); + + Assert.Equal(-1, NumberHelper.Sign(Int64MinValue)); + Assert.Equal(-1, NumberHelper.Sign(NegativeOne)); + + Assert.Equal(1, NumberHelper.Sign(Int64MaxValuePlusOne)); + Assert.Equal(1, NumberHelper.Sign(UInt64MaxValue)); + } + + [Fact] + public static void TryCreateFromByteTest() + { + BigInteger result; + + Assert.True(NumberHelper.TryCreate(0x00, out result)); + Assert.Equal(Zero, result); + + Assert.True(NumberHelper.TryCreate(0x01, out result)); + Assert.Equal(One, result); + + Assert.True(NumberHelper.TryCreate(0x7F, out result)); + Assert.Equal(SByteMaxValue, result); + + Assert.True(NumberHelper.TryCreate(0x80, out result)); + Assert.Equal(SByteMaxValuePlusOne, result); + + Assert.True(NumberHelper.TryCreate(0xFF, out result)); + Assert.Equal(ByteMaxValue, result); + } + + [Fact] + public static void TryCreateFromCharTest() + { + BigInteger result; + + Assert.True(NumberHelper.TryCreate((char)0x0000, out result)); + Assert.Equal(Zero, result); + + Assert.True(NumberHelper.TryCreate((char)0x0001, out result)); + Assert.Equal(One, result); + + Assert.True(NumberHelper.TryCreate((char)0x7FFF, out result)); + Assert.Equal(Int16MaxValue, result); + + Assert.True(NumberHelper.TryCreate((char)0x8000, out result)); + Assert.Equal(Int16MaxValuePlusOne, result); + + Assert.True(NumberHelper.TryCreate((char)0xFFFF, out result)); + Assert.Equal(UInt16MaxValue, result); + } + + [Fact] + public static void TryCreateFromInt16Test() + { + BigInteger result; + + Assert.True(NumberHelper.TryCreate(0x0000, out result)); + Assert.Equal(Zero, result); + + Assert.True(NumberHelper.TryCreate(0x0001, out result)); + Assert.Equal(One, result); + + Assert.True(NumberHelper.TryCreate(0x7FFF, out result)); + Assert.Equal(Int16MaxValue, result); + + Assert.True(NumberHelper.TryCreate(unchecked((short)0x8000), out result)); + Assert.Equal(Int16MinValue, result); + + Assert.True(NumberHelper.TryCreate(unchecked((short)0xFFFF), out result)); + Assert.Equal(NegativeOne, result); + } + + [Fact] + public static void TryCreateFromInt32Test() + { + BigInteger result; + + Assert.True(NumberHelper.TryCreate(0x00000000, out result)); + Assert.Equal(Zero, result); + + Assert.True(NumberHelper.TryCreate(0x00000001, out result)); + Assert.Equal(One, result); + + Assert.True(NumberHelper.TryCreate(0x7FFFFFFF, out result)); + Assert.Equal(Int32MaxValue, result); + + Assert.True(NumberHelper.TryCreate(unchecked((int)0x80000000), out result)); + Assert.Equal(Int32MinValue, result); + + Assert.True(NumberHelper.TryCreate(unchecked((int)0xFFFFFFFF), out result)); + Assert.Equal(NegativeOne, result); + } + + [Fact] + public static void TryCreateFromInt64Test() + { + BigInteger result; + + Assert.True(NumberHelper.TryCreate(0x00000000, out result)); + Assert.Equal(Zero, result); + + Assert.True(NumberHelper.TryCreate(0x00000001, out result)); + Assert.Equal(One, result); + + Assert.True(NumberHelper.TryCreate(0x7FFFFFFFFFFFFFFF, out result)); + Assert.Equal(Int64MaxValue, result); + + Assert.True(NumberHelper.TryCreate(unchecked((long)0x8000000000000000), out result)); + Assert.Equal(Int64MinValue, result); + + Assert.True(NumberHelper.TryCreate(unchecked((long)0xFFFFFFFFFFFFFFFF), out result)); + Assert.Equal(NegativeOne, result); + } + + [Fact] + public static void TryCreateFromIntPtrTest() + { + BigInteger result; + + if (Environment.Is64BitProcess) + { + Assert.True(NumberHelper.TryCreate(unchecked((nint)0x00000000), out result)); + Assert.Equal(Zero, result); + + Assert.True(NumberHelper.TryCreate(unchecked((nint)0x00000001), out result)); + Assert.Equal(One, result); + + Assert.True(NumberHelper.TryCreate(unchecked((nint)0x7FFFFFFFFFFFFFFF), out result)); + Assert.Equal(Int64MaxValue, result); + + Assert.True(NumberHelper.TryCreate(unchecked((nint)0x8000000000000000), out result)); + Assert.Equal(Int64MinValue, result); + + Assert.True(NumberHelper.TryCreate(unchecked((nint)0xFFFFFFFFFFFFFFFF), out result)); + Assert.Equal(NegativeOne, result); + } + else + { + Assert.True(NumberHelper.TryCreate((nint)0x00000000, out result)); + Assert.Equal(Zero, result); + + Assert.True(NumberHelper.TryCreate((nint)0x00000001, out result)); + Assert.Equal(One, result); + + Assert.True(NumberHelper.TryCreate((nint)0x7FFFFFFF, out result)); + Assert.Equal(Int32MaxValue, result); + + Assert.True(NumberHelper.TryCreate(unchecked((nint)0x80000000), out result)); + Assert.Equal(Int32MinValue, result); + + Assert.True(NumberHelper.TryCreate(unchecked((nint)0xFFFFFFFF), out result)); + Assert.Equal(NegativeOne, result); + } + } + + [Fact] + public static void TryCreateFromSByteTest() + { + BigInteger result; + + Assert.True(NumberHelper.TryCreate(0x00, out result)); + Assert.Equal(Zero, result); + + Assert.True(NumberHelper.TryCreate(0x01, out result)); + Assert.Equal(One, result); + + Assert.True(NumberHelper.TryCreate(0x7F, out result)); + Assert.Equal(SByteMaxValue, result); + + Assert.True(NumberHelper.TryCreate(unchecked((sbyte)0x80), out result)); + Assert.Equal(SByteMinValue, result); + + Assert.True(NumberHelper.TryCreate(unchecked((sbyte)0xFF), out result)); + Assert.Equal(NegativeOne, result); + } + + [Fact] + public static void TryCreateFromUInt16Test() + { + BigInteger result; + + Assert.True(NumberHelper.TryCreate(0x0000, out result)); + Assert.Equal(Zero, result); + + Assert.True(NumberHelper.TryCreate(0x0001, out result)); + Assert.Equal(One, result); + + Assert.True(NumberHelper.TryCreate(0x7FFF, out result)); + Assert.Equal(Int16MaxValue, result); + + Assert.True(NumberHelper.TryCreate(0x8000, out result)); + Assert.Equal(Int16MaxValuePlusOne, result); + + Assert.True(NumberHelper.TryCreate(0xFFFF, out result)); + Assert.Equal(UInt16MaxValue, result); + } + + [Fact] + public static void TryCreateFromUInt32Test() + { + BigInteger result; + + Assert.True(NumberHelper.TryCreate(0x00000000, out result)); + Assert.Equal(Zero, result); + + Assert.True(NumberHelper.TryCreate(0x00000001, out result)); + Assert.Equal(One, result); + + Assert.True(NumberHelper.TryCreate(0x7FFFFFFF, out result)); + Assert.Equal(Int32MaxValue, result); + + Assert.True(NumberHelper.TryCreate(0x80000000, out result)); + Assert.Equal(Int32MaxValuePlusOne, result); + + Assert.True(NumberHelper.TryCreate(0xFFFFFFFF, out result)); + Assert.Equal(UInt32MaxValue, result); + } + + [Fact] + public static void TryCreateFromUInt64Test() + { + BigInteger result; + + Assert.True(NumberHelper.TryCreate(0x00000000, out result)); + Assert.Equal(Zero, result); + + Assert.True(NumberHelper.TryCreate(0x00000001, out result)); + Assert.Equal(One, result); + + Assert.True(NumberHelper.TryCreate(0x7FFFFFFFFFFFFFFF, out result)); + Assert.Equal(Int64MaxValue, result); + + Assert.True(NumberHelper.TryCreate(0x8000000000000000, out result)); + Assert.Equal(Int64MaxValuePlusOne, result); + + Assert.True(NumberHelper.TryCreate(0xFFFFFFFFFFFFFFFF, out result)); + Assert.Equal(UInt64MaxValue, result); + } + + [Fact] + public static void TryCreateFromUIntPtrTest() + { + BigInteger result; + + if (Environment.Is64BitProcess) + { + Assert.True(NumberHelper.TryCreate(unchecked((nuint)0x00000000), out result)); + Assert.Equal(Zero, result); + + Assert.True(NumberHelper.TryCreate(unchecked((nuint)0x00000001), out result)); + Assert.Equal(One, result); + + Assert.True(NumberHelper.TryCreate(unchecked((nuint)0x7FFFFFFFFFFFFFFF), out result)); + Assert.Equal(Int64MaxValue, result); + + Assert.True(NumberHelper.TryCreate(unchecked((nuint)0x8000000000000000), out result)); + Assert.Equal(Int64MaxValuePlusOne, result); + + Assert.True(NumberHelper.TryCreate(unchecked((nuint)0xFFFFFFFFFFFFFFFF), out result)); + Assert.Equal(UInt64MaxValue, result); + } + else + { + Assert.True(NumberHelper.TryCreate((nuint)0x00000000, out result)); + Assert.Equal(Zero, result); + + Assert.True(NumberHelper.TryCreate((nuint)0x00000001, out result)); + Assert.Equal(One, result); + + Assert.True(NumberHelper.TryCreate((nuint)0x7FFFFFFF, out result)); + Assert.Equal(Int32MaxValue, result); + + Assert.True(NumberHelper.TryCreate(unchecked((nuint)0x80000000), out result)); + Assert.Equal(Int32MaxValuePlusOne, result); + + Assert.True(NumberHelper.TryCreate(unchecked((nuint)0xFFFFFFFF), out result)); + Assert.Equal(UInt32MaxValue, result); + } + } + + [Fact] + public static void GetByteCountTest() + { + Assert.Equal(4, BinaryIntegerHelper.GetByteCount(Zero)); + Assert.Equal(4, BinaryIntegerHelper.GetByteCount(One)); + Assert.Equal(8, BinaryIntegerHelper.GetByteCount(Int64MaxValue)); + + Assert.Equal(8, BinaryIntegerHelper.GetByteCount(Int64MinValue)); + Assert.Equal(4, BinaryIntegerHelper.GetByteCount(NegativeOne)); + + Assert.Equal(8, BinaryIntegerHelper.GetByteCount(Int64MaxValuePlusOne)); + Assert.Equal(8, BinaryIntegerHelper.GetByteCount(UInt64MaxValue)); + } + + [Fact] + public static void TryWriteLittleEndianTest() + { + Span destination = stackalloc byte[8]; + int bytesWritten = 0; + + Assert.True(BinaryIntegerHelper.TryWriteLittleEndian(Zero, destination, out bytesWritten)); + Assert.Equal(4, bytesWritten); + Assert.Equal(new byte[] { 0x00, 0x00, 0x00, 0x00 }, destination.Slice(0, 4).ToArray()); + + Assert.True(BinaryIntegerHelper.TryWriteLittleEndian(One, destination, out bytesWritten)); + Assert.Equal(4, bytesWritten); + Assert.Equal(new byte[] { 0x01, 0x00, 0x00, 0x00 }, destination.Slice(0, 4).ToArray()); + + Assert.True(BinaryIntegerHelper.TryWriteLittleEndian(Int64MaxValue, destination, out bytesWritten)); + Assert.Equal(8, bytesWritten); + Assert.Equal(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F }, destination.Slice(0, 8).ToArray()); + + Assert.True(BinaryIntegerHelper.TryWriteLittleEndian(Int64MinValue, destination, out bytesWritten)); + Assert.Equal(8, bytesWritten); + Assert.Equal(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }, destination.Slice(0, 8).ToArray()); + + Assert.True(BinaryIntegerHelper.TryWriteLittleEndian(NegativeOne, destination, out bytesWritten)); + Assert.Equal(4, bytesWritten); + Assert.Equal(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }, destination.Slice(0, 4).ToArray()); + + Assert.True(BinaryIntegerHelper.TryWriteLittleEndian(Int64MaxValuePlusOne, destination, out bytesWritten)); + Assert.Equal(8, bytesWritten); + Assert.Equal(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }, destination.Slice(0, 8).ToArray()); + + Assert.True(BinaryIntegerHelper.TryWriteLittleEndian(UInt64MaxValue, destination, out bytesWritten)); + Assert.Equal(8, bytesWritten); + Assert.Equal(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, destination.Slice(0, 8).ToArray()); + + Assert.False(BinaryIntegerHelper.TryWriteLittleEndian(default, Span.Empty, out bytesWritten)); + Assert.Equal(0, bytesWritten); + Assert.Equal(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, destination.ToArray()); + } + + [Fact] + public static void op_LeftShiftTest() + { + Assert.Equal(Zero, ShiftOperatorsHelper.op_LeftShift(Zero, 1)); + Assert.Equal(Two, ShiftOperatorsHelper.op_LeftShift(One, 1)); + Assert.Equal(unchecked((BigInteger)0xFFFFFFFFFFFFFFFE), ShiftOperatorsHelper.op_LeftShift(Int64MaxValue, 1)); + + Assert.Equal(NegativeTwoPow64, ShiftOperatorsHelper.op_LeftShift(Int64MinValue, 1)); + Assert.Equal(unchecked((BigInteger)(int)0xFFFFFFFE), ShiftOperatorsHelper.op_LeftShift(NegativeOne, 1)); + + Assert.Equal(TwoPow64, ShiftOperatorsHelper.op_LeftShift(Int64MaxValuePlusOne, 1)); + Assert.Equal(UInt64MaxValueTimesTwo, ShiftOperatorsHelper.op_LeftShift(UInt64MaxValue, 1)); + } + + [Fact] + public static void op_RightShiftTest() + { + Assert.Equal(Zero, ShiftOperatorsHelper.op_RightShift(Zero, 1)); + Assert.Equal(Zero, ShiftOperatorsHelper.op_RightShift(One, 1)); + Assert.Equal((BigInteger)0x3FFFFFFFFFFFFFFF, ShiftOperatorsHelper.op_RightShift(Int64MaxValue, 1)); + + Assert.Equal(unchecked((BigInteger)(long)0xC000000000000000), ShiftOperatorsHelper.op_RightShift(Int64MinValue, 1)); + Assert.Equal(NegativeOne, ShiftOperatorsHelper.op_RightShift(NegativeOne, 1)); + + Assert.Equal(unchecked((BigInteger)0x4000000000000000), ShiftOperatorsHelper.op_RightShift(Int64MaxValuePlusOne, 1)); + Assert.Equal(Int64MaxValue, ShiftOperatorsHelper.op_RightShift(UInt64MaxValue, 1)); + } + + [Fact] + public static void op_UnsignedRightShiftTest() + { + Assert.Equal(Zero, ShiftOperatorsHelper.op_UnsignedRightShift(Zero, 1)); + Assert.Equal(Zero, ShiftOperatorsHelper.op_UnsignedRightShift(One, 1)); + Assert.Equal((BigInteger)0x3FFFFFFFFFFFFFFF, ShiftOperatorsHelper.op_UnsignedRightShift(Int64MaxValue, 1)); + + Assert.Equal((BigInteger)0x4000000000000000, ShiftOperatorsHelper.op_UnsignedRightShift(Int64MinValue, 1)); + Assert.Equal(Int32MaxValue, ShiftOperatorsHelper.op_UnsignedRightShift(NegativeOne, 1)); + + Assert.Equal((BigInteger)0x4000000000000000, ShiftOperatorsHelper.op_UnsignedRightShift(Int64MaxValuePlusOne, 1)); + Assert.Equal(Int64MaxValue, ShiftOperatorsHelper.op_UnsignedRightShift(UInt64MaxValue, 1)); + } + + [Fact] + public static void op_SubtractionTest() + { + Assert.Equal(NegativeOne, SubtractionOperatorsHelper.op_Subtraction(Zero, 1)); + Assert.Equal(Zero, SubtractionOperatorsHelper.op_Subtraction(One, 1)); + Assert.Equal(Int64MaxValueMinusOne, SubtractionOperatorsHelper.op_Subtraction(Int64MaxValue, 1)); + + Assert.Equal(Int64MinValueMinusOne, SubtractionOperatorsHelper.op_Subtraction(Int64MinValue, 1)); + Assert.Equal(NegativeTwo, SubtractionOperatorsHelper.op_Subtraction(NegativeOne, 1)); + + Assert.Equal(Int64MaxValue, SubtractionOperatorsHelper.op_Subtraction(Int64MaxValuePlusOne, 1)); + Assert.Equal(UInt64MaxValueMinusOne, SubtractionOperatorsHelper.op_Subtraction(UInt64MaxValue, 1)); + } + + [Fact] + public static void op_CheckedSubtractionTest() + { + Assert.Equal(NegativeOne, SubtractionOperatorsHelper.op_CheckedSubtraction(Zero, 1)); + Assert.Equal(Zero, SubtractionOperatorsHelper.op_CheckedSubtraction(One, 1)); + Assert.Equal(Int64MaxValueMinusOne, SubtractionOperatorsHelper.op_CheckedSubtraction(Int64MaxValue, 1)); + + Assert.Equal(Int64MinValueMinusOne, SubtractionOperatorsHelper.op_CheckedSubtraction(Int64MinValue, 1)); + Assert.Equal(NegativeTwo, SubtractionOperatorsHelper.op_CheckedSubtraction(NegativeOne, 1)); + + Assert.Equal(Int64MaxValue, SubtractionOperatorsHelper.op_CheckedSubtraction(Int64MaxValuePlusOne, 1)); + Assert.Equal(UInt64MaxValueMinusOne, SubtractionOperatorsHelper.op_CheckedSubtraction(UInt64MaxValue, 1)); + } + + [Fact] + public static void op_UnaryNegationTest() + { + Assert.Equal(Zero, UnaryNegationOperatorsHelper.op_UnaryNegation(Zero)); + Assert.Equal(NegativeOne, UnaryNegationOperatorsHelper.op_UnaryNegation(One)); + Assert.Equal(Int64MinValuePlusOne, UnaryNegationOperatorsHelper.op_UnaryNegation(Int64MaxValue)); + + Assert.Equal(Int64MaxValuePlusOne, UnaryNegationOperatorsHelper.op_UnaryNegation(Int64MinValue)); + Assert.Equal(One, UnaryNegationOperatorsHelper.op_UnaryNegation(NegativeOne)); + + Assert.Equal(Int64MinValue, UnaryNegationOperatorsHelper.op_UnaryNegation(Int64MaxValuePlusOne)); + Assert.Equal(NegativeTwoPow64PlusOne, UnaryNegationOperatorsHelper.op_UnaryNegation(UInt64MaxValue)); + } + + [Fact] + public static void op_CheckedUnaryNegationTest() + { + Assert.Equal(Zero, UnaryNegationOperatorsHelper.op_CheckedUnaryNegation(Zero)); + Assert.Equal(NegativeOne, UnaryNegationOperatorsHelper.op_CheckedUnaryNegation(One)); + Assert.Equal(Int64MinValuePlusOne, UnaryNegationOperatorsHelper.op_CheckedUnaryNegation(Int64MaxValue)); + + Assert.Equal(Int64MaxValuePlusOne, UnaryNegationOperatorsHelper.op_CheckedUnaryNegation(Int64MinValue)); + Assert.Equal(One, UnaryNegationOperatorsHelper.op_CheckedUnaryNegation(NegativeOne)); + + Assert.Equal(Int64MinValue, UnaryNegationOperatorsHelper.op_CheckedUnaryNegation(Int64MaxValuePlusOne)); + Assert.Equal(NegativeTwoPow64PlusOne, UnaryNegationOperatorsHelper.op_CheckedUnaryNegation(UInt64MaxValue)); + } + + [Fact] + public static void op_UnaryPlusTest() + { + Assert.Equal(Zero, UnaryPlusOperatorsHelper.op_UnaryPlus(Zero)); + Assert.Equal(One, UnaryPlusOperatorsHelper.op_UnaryPlus(One)); + Assert.Equal(Int64MaxValue, UnaryPlusOperatorsHelper.op_UnaryPlus(Int64MaxValue)); + + Assert.Equal(Int64MinValue, UnaryPlusOperatorsHelper.op_UnaryPlus(Int64MinValue)); + Assert.Equal(NegativeOne, UnaryPlusOperatorsHelper.op_UnaryPlus(NegativeOne)); + + Assert.Equal(Int64MaxValuePlusOne, UnaryPlusOperatorsHelper.op_UnaryPlus(Int64MaxValuePlusOne)); + Assert.Equal(UInt64MaxValue, UnaryPlusOperatorsHelper.op_UnaryPlus(UInt64MaxValue)); + } + } +} 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 4b9dbea05bf6b0..75d08c9efeea46 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 @@ -54,6 +54,10 @@ + + + + From 745497829fd2d9c95c3b576332d5770117ec0842 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sun, 8 May 2022 07:55:16 -0700 Subject: [PATCH 3/3] Addressing PR feedback --- .../src/System/Numerics/BigInteger.cs | 324 +++++++++--------- .../src/System/ThrowHelper.cs | 6 + 2 files changed, 167 insertions(+), 163 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs index e4edb7101c9c2b..0dc15c9e5ca4dc 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs @@ -473,8 +473,14 @@ public BigInteger(ReadOnlySpan value, bool isUnsigned = false, bool isBigE internal BigInteger(int n, uint[]? rgu) { + if ((rgu is not null) && (rgu.Length > MaxLength)) + { + ThrowHelper.ThrowOverflowException(); + } + _sign = n; _bits = rgu; + AssertValid(); } @@ -486,6 +492,11 @@ internal BigInteger(int n, uint[]? rgu) /// The bool indicating the sign of the value. private BigInteger(ReadOnlySpan value, bool negative) { + if (value.Length > MaxLength) + { + ThrowHelper.ThrowOverflowException(); + } + int len; // Try to conserve space as much as possible by checking for wasted leading span entries @@ -521,6 +532,11 @@ private BigInteger(ReadOnlySpan value, bool negative) /// private BigInteger(Span value) { + if (value.Length > MaxLength) + { + ThrowHelper.ThrowOverflowException(); + } + int dwordCount = value.Length; bool isNegative = dwordCount > 0 && ((value[dwordCount - 1] & kuMaskHighBit) == kuMaskHighBit); @@ -605,6 +621,8 @@ private BigInteger(Span value) public static BigInteger MinusOne { get { return s_bnMinusOneInt; } } + internal static int MaxLength => Array.MaxLength / sizeof(uint); + public bool IsPowerOfTwo { get @@ -750,9 +768,9 @@ public static BigInteger DivRem(BigInteger dividend, BigInteger divisor, out Big uint[]? bitsFromPool = null; int size = dividend._bits.Length; - Span quotient = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span quotient = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); try { @@ -780,15 +798,15 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] { uint[]? remainderFromPool = null; int size = dividend._bits.Length; - Span rest = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : remainderFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span rest = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : remainderFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); uint[]? quotientFromPool = null; size = dividend._bits.Length - divisor._bits.Length + 1; - Span quotient = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : quotientFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span quotient = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : quotientFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); BigIntegerCalculator.Divide(dividend._bits, divisor._bits, quotient, rest); @@ -903,9 +921,9 @@ private static BigInteger GreatestCommonDivisor(ReadOnlySpan leftBits, Rea } else if (rightBits.Length == 2) { - Span bits = (leftBits.Length <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(leftBits.Length)).Slice(0, leftBits.Length); + Span bits = (leftBits.Length <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(leftBits.Length)).Slice(0, leftBits.Length); BigIntegerCalculator.Remainder(leftBits, rightBits, bits); @@ -916,9 +934,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] } else { - Span bits = (leftBits.Length <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(leftBits.Length)).Slice(0, leftBits.Length); + Span bits = (leftBits.Length <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(leftBits.Length)).Slice(0, leftBits.Length); BigIntegerCalculator.Gcd(leftBits, rightBits, bits); result = new BigInteger(bits, negative: false); @@ -972,9 +990,9 @@ public static BigInteger ModPow(BigInteger value, BigInteger exponent, BigIntege { int size = (modulus._bits?.Length ?? 1) << 1; uint[]? bitsFromPool = null; - Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); bits.Clear(); if (trivialValue) { @@ -1033,9 +1051,9 @@ public static BigInteger Pow(BigInteger value, int exponent) return value; int size = BigIntegerCalculator.PowBound(power, 1); - Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); bits.Clear(); BigIntegerCalculator.Pow(NumericsHelpers.Abs(value._sign), power, bits); @@ -1044,9 +1062,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] else { int size = BigIntegerCalculator.PowBound(power, value._bits!.Length); - Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); bits.Clear(); BigIntegerCalculator.Pow(value._bits, power, bits); @@ -1598,9 +1616,9 @@ private static BigInteger Add(ReadOnlySpan leftBits, int leftSign, ReadOnl Debug.Assert(!rightBits.IsEmpty); int size = rightBits.Length + 1; - Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); BigIntegerCalculator.Add(rightBits, NumericsHelpers.Abs(leftSign), bits); result = new BigInteger(bits, leftSign < 0); @@ -1610,9 +1628,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] Debug.Assert(!leftBits.IsEmpty); int size = leftBits.Length + 1; - Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); BigIntegerCalculator.Add(leftBits, NumericsHelpers.Abs(rightSign), bits); result = new BigInteger(bits, leftSign < 0); @@ -1622,9 +1640,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] Debug.Assert(!leftBits.IsEmpty && !rightBits.IsEmpty); int size = rightBits.Length + 1; - Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); BigIntegerCalculator.Add(rightBits, leftBits, bits); result = new BigInteger(bits, leftSign < 0); @@ -1634,9 +1652,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] Debug.Assert(!leftBits.IsEmpty && !rightBits.IsEmpty); int size = leftBits.Length + 1; - Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); BigIntegerCalculator.Add(leftBits, rightBits, bits); result = new BigInteger(bits, leftSign < 0); @@ -1676,9 +1694,9 @@ private static BigInteger Subtract(ReadOnlySpan leftBits, int leftSign, Re Debug.Assert(!rightBits.IsEmpty); int size = rightBits.Length; - Span bits = (size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = (size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); BigIntegerCalculator.Subtract(rightBits, NumericsHelpers.Abs(leftSign), bits); result = new BigInteger(bits, leftSign >= 0); @@ -1688,9 +1706,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] Debug.Assert(!leftBits.IsEmpty); int size = leftBits.Length; - Span bits = (size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = (size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); BigIntegerCalculator.Subtract(leftBits, NumericsHelpers.Abs(rightSign), bits); result = new BigInteger(bits, leftSign < 0); @@ -1698,9 +1716,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] else if (BigIntegerCalculator.Compare(leftBits, rightBits) < 0) { int size = rightBits.Length; - Span bits = (size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = (size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); BigIntegerCalculator.Subtract(rightBits, leftBits, bits); result = new BigInteger(bits, leftSign >= 0); @@ -1710,9 +1728,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] Debug.Assert(!leftBits.IsEmpty && !rightBits.IsEmpty); int size = leftBits.Length; - Span bits = (size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = (size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); BigIntegerCalculator.Subtract(leftBits, rightBits, bits); result = new BigInteger(bits, leftSign < 0); @@ -2032,23 +2050,23 @@ public static explicit operator decimal(BigInteger value) uint[]? leftBufferFromPool = null; int size = (left._bits?.Length ?? 1) + 1; - Span x = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : leftBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span x = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : leftBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); x = x.Slice(0, left.WriteTo(x)); uint[]? rightBufferFromPool = null; size = (right._bits?.Length ?? 1) + 1; - Span y = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : rightBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span y = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : rightBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); y = y.Slice(0, right.WriteTo(y)); uint[]? resultBufferFromPool = null; size = Math.Max(x.Length, y.Length); - Span z = (size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : resultBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span z = (size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : resultBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); for (int i = 0; i < z.Length; i++) { @@ -2088,23 +2106,23 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] uint[]? leftBufferFromPool = null; int size = (left._bits?.Length ?? 1) + 1; - Span x = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : leftBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span x = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : leftBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); x = x.Slice(0, left.WriteTo(x)); uint[]? rightBufferFromPool = null; size = (right._bits?.Length ?? 1) + 1; - Span y = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : rightBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span y = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : rightBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); y = y.Slice(0, right.WriteTo(y)); uint[]? resultBufferFromPool = null; size = Math.Max(x.Length, y.Length); - Span z = (size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : resultBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span z = (size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : resultBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); for (int i = 0; i < z.Length; i++) { @@ -2139,23 +2157,23 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] uint[]? leftBufferFromPool = null; int size = (left._bits?.Length ?? 1) + 1; - Span x = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : leftBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span x = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : leftBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); x = x.Slice(0, left.WriteTo(x)); uint[]? rightBufferFromPool = null; size = (right._bits?.Length ?? 1) + 1; - Span y = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : rightBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span y = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : rightBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); y = y.Slice(0, right.WriteTo(y)); uint[]? resultBufferFromPool = null; size = Math.Max(x.Length, y.Length); - Span z = (size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : resultBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span z = (size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : resultBufferFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); for (int i = 0; i < z.Length; i++) { @@ -2193,16 +2211,16 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] uint[]? xdFromPool = null; int xl = value._bits?.Length ?? 1; - Span xd = (xl <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : xdFromPool = ArrayPool.Shared.Rent(xl)).Slice(0, xl); + Span xd = (xl <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : xdFromPool = ArrayPool.Shared.Rent(xl)).Slice(0, xl); bool negx = value.GetPartsForBitManipulation(xd); int zl = xl + digitShift + 1; uint[]? zdFromPool = null; - Span zd = ((uint)zl <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : zdFromPool = ArrayPool.Shared.Rent(zl)).Slice(0, zl); + Span zd = ((uint)zl <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : zdFromPool = ArrayPool.Shared.Rent(zl)).Slice(0, zl); zd.Clear(); uint carry = 0; @@ -2254,9 +2272,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] uint[]? xdFromPool = null; int xl = value._bits?.Length ?? 1; - Span xd = (xl <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : xdFromPool = ArrayPool.Shared.Rent(xl)).Slice(0, xl); + Span xd = (xl <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : xdFromPool = ArrayPool.Shared.Rent(xl)).Slice(0, xl); bool negx = value.GetPartsForBitManipulation(xd); bool trackSignBit = false; @@ -2282,9 +2300,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] uint[]? zdFromPool = null; int zl = Math.Max(xl - digitShift, 0) + (trackSignBit ? 1 : 0); - Span zd = ((uint)zl <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : zdFromPool = ArrayPool.Shared.Rent(zl)).Slice(0, zl); + Span zd = ((uint)zl <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : zdFromPool = ArrayPool.Shared.Rent(zl)).Slice(0, zl); zd.Clear(); if (smallShift == 0) @@ -2393,9 +2411,9 @@ private static BigInteger Multiply(ReadOnlySpan left, int leftSign, ReadOn Debug.Assert(!right.IsEmpty); int size = right.Length + 1; - Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); BigIntegerCalculator.Multiply(right, NumericsHelpers.Abs(leftSign), bits); result = new BigInteger(bits, (leftSign < 0) ^ (rightSign < 0)); @@ -2405,9 +2423,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] Debug.Assert(!left.IsEmpty); int size = left.Length + 1; - Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); BigIntegerCalculator.Multiply(left, NumericsHelpers.Abs(rightSign), bits); result = new BigInteger(bits, (leftSign < 0) ^ (rightSign < 0)); @@ -2415,9 +2433,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] else if (left == right) { int size = left.Length + right.Length; - Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); BigIntegerCalculator.Square(left, bits); result = new BigInteger(bits, negative: false); @@ -2427,9 +2445,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] Debug.Assert(!left.IsEmpty && !right.IsEmpty); int size = left.Length + right.Length; - Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); bits.Clear(); BigIntegerCalculator.Multiply(right, left, bits); @@ -2440,9 +2458,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] Debug.Assert(!left.IsEmpty && !right.IsEmpty); int size = left.Length + right.Length; - Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); bits.Clear(); BigIntegerCalculator.Multiply(left, right, bits); @@ -2482,9 +2500,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] Debug.Assert(dividend._bits != null); int size = dividend._bits.Length; - Span quotient = ((uint)size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : quotientFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span quotient = ((uint)size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : quotientFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); try { @@ -2508,9 +2526,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] else { int size = dividend._bits.Length - divisor._bits.Length + 1; - Span quotient = ((uint)size < BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : quotientFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span quotient = ((uint)size < BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : quotientFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); BigIntegerCalculator.Divide(dividend._bits, divisor._bits, quotient); var result = new BigInteger(quotient, (dividend._sign < 0) ^ (divisor._sign < 0)); @@ -2558,9 +2576,9 @@ stackalloc uint[BigIntegerCalculator.StackAllocThreshold] uint[]? bitsFromPool = null; int size = dividend._bits.Length; - Span bits = (size <= BigIntegerCalculator.StackAllocThreshold ? - stackalloc uint[BigIntegerCalculator.StackAllocThreshold] - : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); + Span bits = (size <= BigIntegerCalculator.StackAllocThreshold + ? stackalloc uint[BigIntegerCalculator.StackAllocThreshold] + : bitsFromPool = ArrayPool.Shared.Rent(size)).Slice(0, size); BigIntegerCalculator.Remainder(dividend._bits, divisor._bits, bits); var result = new BigInteger(bits, dividend._sign < 0); @@ -2830,6 +2848,8 @@ private void AssertValid() Debug.Assert(_bits.Length > 1 || _bits[0] >= kuMaskHighBit); // Wasted space: leading zeros could have been truncated Debug.Assert(_bits[_bits.Length - 1] != 0); + // Arrays larger than this can't fit into a Span + Debug.Assert(_bits.Length <= MaxLength); } else { @@ -2941,7 +2961,7 @@ public static BigInteger RotateLeft(BigInteger value, int rotateAmount) int byteCount = (value._bits is null) ? sizeof(int) : (value._bits.Length * 4); // Normalize the rotate amount to drop full rotations - rotateAmount %= (int)(byteCount * 8L); + rotateAmount = (int)(rotateAmount % (byteCount * 8L)); if (rotateAmount == 0) return value; @@ -3076,7 +3096,7 @@ public static BigInteger RotateRight(BigInteger value, int rotateAmount) int byteCount = (value._bits is null) ? sizeof(int) : (value._bits.Length * 4); // Normalize the rotate amount to drop full rotations - rotateAmount %= (int)(byteCount * 8L); + rotateAmount = (int)(rotateAmount % (byteCount * 8L)); if (rotateAmount == 0) return value; @@ -3257,6 +3277,7 @@ public static BigInteger TrailingZeroCount(BigInteger value) /// long IBinaryInteger.GetShortestBitLength() { + AssertValid(); uint[]? bits = _bits; if (bits is null) @@ -3290,6 +3311,7 @@ long IBinaryInteger.GetShortestBitLength() /// int IBinaryInteger.GetByteCount() { + AssertValid(); uint[]? bits = _bits; if (bits is null) @@ -3302,7 +3324,9 @@ int IBinaryInteger.GetByteCount() /// bool IBinaryInteger.TryWriteLittleEndian(Span destination, out int bytesWritten) { + AssertValid(); uint[]? bits = _bits; + int byteCount = (bits is null) ? sizeof(int) : bits.Length * 4; if (destination.Length >= byteCount) @@ -3383,6 +3407,8 @@ bool IBinaryInteger.TryWriteLittleEndian(Span destination, out /// public static BigInteger Log2(BigInteger value) { + value.AssertValid(); + if (IsNegative(value)) { ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException(); @@ -3439,6 +3465,7 @@ public static BigInteger Log2(BigInteger value) public static BigInteger Clamp(BigInteger value, BigInteger min, BigInteger max) { value.AssertValid(); + min.AssertValid(); max.AssertValid(); @@ -3549,6 +3576,10 @@ public static BigInteger CreateChecked(TOther value) { return (nuint)(object)value; } + else if (typeof(TOther) == typeof(BigInteger)) + { + return (BigInteger)(object)value; + } else { ThrowHelper.ThrowNotSupportedException(); @@ -3617,6 +3648,10 @@ public static BigInteger CreateSaturating(TOther value) { return (nuint)(object)value; } + else if (typeof(TOther) == typeof(BigInteger)) + { + return (BigInteger)(object)value; + } else { ThrowHelper.ThrowNotSupportedException(); @@ -3685,6 +3720,10 @@ public static BigInteger CreateTruncating(TOther value) { return (nuint)(object)value; } + else if (typeof(TOther) == typeof(BigInteger)) + { + return (BigInteger)(object)value; + } else { ThrowHelper.ThrowNotSupportedException(); @@ -3705,31 +3744,7 @@ public static BigInteger MaxMagnitude(BigInteger x, BigInteger y) x.AssertValid(); y.AssertValid(); - BigInteger absX = x; - - if (absX < 0) - { - absX = -absX; - - if (absX < 0) - { - return x; - } - } - - BigInteger absY = y; - - if (absY < 0) - { - absY = -absY; - - if (absY < 0) - { - return y; - } - } - - return (absX >= absY) ? x : y; + return (Abs(x) >= Abs(y)) ? x : y; } /// @@ -3738,31 +3753,7 @@ public static BigInteger MinMagnitude(BigInteger x, BigInteger y) x.AssertValid(); y.AssertValid(); - BigInteger absX = x; - - if (absX < 0) - { - absX = -absX; - - if (absX < 0) - { - return y; - } - } - - BigInteger absY = y; - - if (absY < 0) - { - absY = -absY; - - if (absY < 0) - { - return x; - } - } - - return (absX <= absY) ? x : y; + return (Abs(x) <= Abs(y)) ? x : y; } /// @@ -3869,6 +3860,11 @@ public static bool TryCreate(TOther value, out BigInteger result) result = (nuint)(object)value; return true; } + else if (typeof(TOther) == typeof(BigInteger)) + { + result = (BigInteger)(object)value; + return true; + } else { ThrowHelper.ThrowNotSupportedException(); @@ -3890,6 +3886,8 @@ public static bool TryCreate(TOther value, out BigInteger result) /// public static BigInteger operator >>>(BigInteger value, int shiftAmount) { + value.AssertValid(); + if (shiftAmount == 0) return value; diff --git a/src/libraries/System.Runtime.Numerics/src/System/ThrowHelper.cs b/src/libraries/System.Runtime.Numerics/src/System/ThrowHelper.cs index 541bc574003f48..3a73f6e2c94671 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/ThrowHelper.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/ThrowHelper.cs @@ -9,6 +9,12 @@ namespace System [StackTraceHidden] internal static class ThrowHelper { + [DoesNotReturn] + internal static void ThrowOverflowException() + { + throw new OverflowException(); + } + [DoesNotReturn] internal static void ThrowNotSupportedException() {