mirror of
https://github.com/VSadov/Satori.git
synced 2025-06-09 17:44:48 +09:00
[release/9.0] Fix BigInteger.Rotate{Left,Right}
for backport (#112991)
* Add BigInteger.Rotate* tests * Fix BigInteger.Rotate* * avoid stackalloc * Add comment * Fix the unsigned right shift operator of BigInteger (#112879) * Add tests for the shift operator of BigInteger * Fix the unsigned right shift operator of BigInteger * avoid stackalloc * external sign element --------- Co-authored-by: kzrnm <gengesa@gmail.com>
This commit is contained in:
parent
b64f47acec
commit
8670c12404
7 changed files with 1123 additions and 121 deletions
|
@ -3232,7 +3232,27 @@ namespace System.Numerics
|
||||||
public static BigInteger RotateLeft(BigInteger value, int rotateAmount)
|
public static BigInteger RotateLeft(BigInteger value, int rotateAmount)
|
||||||
{
|
{
|
||||||
value.AssertValid();
|
value.AssertValid();
|
||||||
int byteCount = (value._bits is null) ? sizeof(int) : (value._bits.Length * 4);
|
|
||||||
|
bool negx = value._sign < 0;
|
||||||
|
uint smallBits = NumericsHelpers.Abs(value._sign);
|
||||||
|
scoped ReadOnlySpan<uint> bits = value._bits;
|
||||||
|
if (bits.IsEmpty)
|
||||||
|
{
|
||||||
|
bits = new ReadOnlySpan<uint>(in smallBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
int xl = bits.Length;
|
||||||
|
if (negx && (bits[^1] >= kuMaskHighBit) && ((bits[^1] != kuMaskHighBit) || bits.IndexOfAnyExcept(0u) != (bits.Length - 1)))
|
||||||
|
{
|
||||||
|
// We check for a special case where its sign bit could be outside the uint array after 2's complement conversion.
|
||||||
|
// For example given [0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF], its 2's complement is [0x01, 0x00, 0x00]
|
||||||
|
// After a 32 bit right shift, it becomes [0x00, 0x00] which is [0x00, 0x00] when converted back.
|
||||||
|
// The expected result is [0x00, 0x00, 0xFFFFFFFF] (2's complement) or [0x00, 0x00, 0x01] when converted back
|
||||||
|
// If the 2's component's last element is a 0, we will track the sign externally
|
||||||
|
++xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int byteCount = xl * 4;
|
||||||
|
|
||||||
// Normalize the rotate amount to drop full rotations
|
// Normalize the rotate amount to drop full rotations
|
||||||
rotateAmount = (int)(rotateAmount % (byteCount * 8L));
|
rotateAmount = (int)(rotateAmount % (byteCount * 8L));
|
||||||
|
@ -3249,14 +3269,13 @@ namespace System.Numerics
|
||||||
(int digitShift, int smallShift) = Math.DivRem(rotateAmount, kcbitUint);
|
(int digitShift, int smallShift) = Math.DivRem(rotateAmount, kcbitUint);
|
||||||
|
|
||||||
uint[]? xdFromPool = null;
|
uint[]? xdFromPool = null;
|
||||||
int xl = value._bits?.Length ?? 1;
|
|
||||||
|
|
||||||
Span<uint> xd = (xl <= BigIntegerCalculator.StackAllocThreshold)
|
Span<uint> xd = (xl <= BigIntegerCalculator.StackAllocThreshold)
|
||||||
? stackalloc uint[BigIntegerCalculator.StackAllocThreshold]
|
? stackalloc uint[BigIntegerCalculator.StackAllocThreshold]
|
||||||
: xdFromPool = ArrayPool<uint>.Shared.Rent(xl);
|
: xdFromPool = ArrayPool<uint>.Shared.Rent(xl);
|
||||||
xd = xd.Slice(0, xl);
|
xd = xd.Slice(0, xl);
|
||||||
|
xd[^1] = 0;
|
||||||
|
|
||||||
bool negx = value.GetPartsForBitManipulation(xd);
|
bits.CopyTo(xd);
|
||||||
|
|
||||||
int zl = xl;
|
int zl = xl;
|
||||||
uint[]? zdFromPool = null;
|
uint[]? zdFromPool = null;
|
||||||
|
@ -3367,7 +3386,28 @@ namespace System.Numerics
|
||||||
public static BigInteger RotateRight(BigInteger value, int rotateAmount)
|
public static BigInteger RotateRight(BigInteger value, int rotateAmount)
|
||||||
{
|
{
|
||||||
value.AssertValid();
|
value.AssertValid();
|
||||||
int byteCount = (value._bits is null) ? sizeof(int) : (value._bits.Length * 4);
|
|
||||||
|
|
||||||
|
bool negx = value._sign < 0;
|
||||||
|
uint smallBits = NumericsHelpers.Abs(value._sign);
|
||||||
|
scoped ReadOnlySpan<uint> bits = value._bits;
|
||||||
|
if (bits.IsEmpty)
|
||||||
|
{
|
||||||
|
bits = new ReadOnlySpan<uint>(in smallBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
int xl = bits.Length;
|
||||||
|
if (negx && (bits[^1] >= kuMaskHighBit) && ((bits[^1] != kuMaskHighBit) || bits.IndexOfAnyExcept(0u) != (bits.Length - 1)))
|
||||||
|
{
|
||||||
|
// We check for a special case where its sign bit could be outside the uint array after 2's complement conversion.
|
||||||
|
// For example given [0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF], its 2's complement is [0x01, 0x00, 0x00]
|
||||||
|
// After a 32 bit right shift, it becomes [0x00, 0x00] which is [0x00, 0x00] when converted back.
|
||||||
|
// The expected result is [0x00, 0x00, 0xFFFFFFFF] (2's complement) or [0x00, 0x00, 0x01] when converted back
|
||||||
|
// If the 2's component's last element is a 0, we will track the sign externally
|
||||||
|
++xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int byteCount = xl * 4;
|
||||||
|
|
||||||
// Normalize the rotate amount to drop full rotations
|
// Normalize the rotate amount to drop full rotations
|
||||||
rotateAmount = (int)(rotateAmount % (byteCount * 8L));
|
rotateAmount = (int)(rotateAmount % (byteCount * 8L));
|
||||||
|
@ -3384,14 +3424,13 @@ namespace System.Numerics
|
||||||
(int digitShift, int smallShift) = Math.DivRem(rotateAmount, kcbitUint);
|
(int digitShift, int smallShift) = Math.DivRem(rotateAmount, kcbitUint);
|
||||||
|
|
||||||
uint[]? xdFromPool = null;
|
uint[]? xdFromPool = null;
|
||||||
int xl = value._bits?.Length ?? 1;
|
|
||||||
|
|
||||||
Span<uint> xd = (xl <= BigIntegerCalculator.StackAllocThreshold)
|
Span<uint> xd = (xl <= BigIntegerCalculator.StackAllocThreshold)
|
||||||
? stackalloc uint[BigIntegerCalculator.StackAllocThreshold]
|
? stackalloc uint[BigIntegerCalculator.StackAllocThreshold]
|
||||||
: xdFromPool = ArrayPool<uint>.Shared.Rent(xl);
|
: xdFromPool = ArrayPool<uint>.Shared.Rent(xl);
|
||||||
xd = xd.Slice(0, xl);
|
xd = xd.Slice(0, xl);
|
||||||
|
xd[^1] = 0;
|
||||||
|
|
||||||
bool negx = value.GetPartsForBitManipulation(xd);
|
bits.CopyTo(xd);
|
||||||
|
|
||||||
int zl = xl;
|
int zl = xl;
|
||||||
uint[]? zdFromPool = null;
|
uint[]? zdFromPool = null;
|
||||||
|
@ -3438,19 +3477,12 @@ namespace System.Numerics
|
||||||
{
|
{
|
||||||
int carryShift = kcbitUint - smallShift;
|
int carryShift = kcbitUint - smallShift;
|
||||||
|
|
||||||
int dstIndex = 0;
|
int dstIndex = xd.Length - 1;
|
||||||
int srcIndex = digitShift;
|
int srcIndex = digitShift == 0
|
||||||
|
? xd.Length - 1
|
||||||
|
: digitShift - 1;
|
||||||
|
|
||||||
uint carry = 0;
|
uint carry = xd[digitShift] << carryShift;
|
||||||
|
|
||||||
if (digitShift == 0)
|
|
||||||
{
|
|
||||||
carry = xd[^1] << carryShift;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
carry = xd[srcIndex - 1] << carryShift;
|
|
||||||
}
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -3459,22 +3491,22 @@ namespace System.Numerics
|
||||||
zd[dstIndex] = (part >> smallShift) | carry;
|
zd[dstIndex] = (part >> smallShift) | carry;
|
||||||
carry = part << carryShift;
|
carry = part << carryShift;
|
||||||
|
|
||||||
dstIndex++;
|
dstIndex--;
|
||||||
srcIndex++;
|
srcIndex--;
|
||||||
}
|
}
|
||||||
while (srcIndex < xd.Length);
|
while ((uint)srcIndex < (uint)xd.Length); // is equivalent to (srcIndex >= 0 && srcIndex < xd.Length)
|
||||||
|
|
||||||
srcIndex = 0;
|
srcIndex = xd.Length - 1;
|
||||||
|
|
||||||
while (dstIndex < zd.Length)
|
while ((uint)dstIndex < (uint)zd.Length) // is equivalent to (dstIndex >= 0 && dstIndex < zd.Length)
|
||||||
{
|
{
|
||||||
uint part = xd[srcIndex];
|
uint part = xd[srcIndex];
|
||||||
|
|
||||||
zd[dstIndex] = (part >> smallShift) | carry;
|
zd[dstIndex] = (part >> smallShift) | carry;
|
||||||
carry = part << carryShift;
|
carry = part << carryShift;
|
||||||
|
|
||||||
dstIndex++;
|
dstIndex--;
|
||||||
srcIndex++;
|
srcIndex--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5232,13 +5264,32 @@ namespace System.Numerics
|
||||||
|
|
||||||
BigInteger result;
|
BigInteger result;
|
||||||
|
|
||||||
|
bool negx = value._sign < 0;
|
||||||
|
uint smallBits = NumericsHelpers.Abs(value._sign);
|
||||||
|
scoped ReadOnlySpan<uint> bits = value._bits;
|
||||||
|
if (bits.IsEmpty)
|
||||||
|
{
|
||||||
|
bits = new ReadOnlySpan<uint>(in smallBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
int xl = bits.Length;
|
||||||
|
if (negx && (bits[^1] >= kuMaskHighBit) && ((bits[^1] != kuMaskHighBit) || bits.IndexOfAnyExcept(0u) != (bits.Length - 1)))
|
||||||
|
{
|
||||||
|
// For a shift of N x 32 bit,
|
||||||
|
// We check for a special case where its sign bit could be outside the uint array after 2's complement conversion.
|
||||||
|
// For example given [0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF], its 2's complement is [0x01, 0x00, 0x00]
|
||||||
|
// After a 32 bit right shift, it becomes [0x00, 0x00] which is [0x00, 0x00] when converted back.
|
||||||
|
// The expected result is [0x00, 0x00, 0xFFFFFFFF] (2's complement) or [0x00, 0x00, 0x01] when converted back
|
||||||
|
// If the 2's component's last element is a 0, we will track the sign externally
|
||||||
|
++xl;
|
||||||
|
}
|
||||||
|
|
||||||
uint[]? xdFromPool = null;
|
uint[]? xdFromPool = null;
|
||||||
int xl = value._bits?.Length ?? 1;
|
|
||||||
Span<uint> xd = (xl <= BigIntegerCalculator.StackAllocThreshold
|
Span<uint> xd = (xl <= BigIntegerCalculator.StackAllocThreshold
|
||||||
? stackalloc uint[BigIntegerCalculator.StackAllocThreshold]
|
? stackalloc uint[BigIntegerCalculator.StackAllocThreshold]
|
||||||
: xdFromPool = ArrayPool<uint>.Shared.Rent(xl)).Slice(0, xl);
|
: xdFromPool = ArrayPool<uint>.Shared.Rent(xl)).Slice(0, xl);
|
||||||
|
xd[^1] = 0;
|
||||||
bool negx = value.GetPartsForBitManipulation(xd);
|
bits.CopyTo(xd);
|
||||||
|
|
||||||
if (negx)
|
if (negx)
|
||||||
{
|
{
|
||||||
|
|
|
@ -108,8 +108,14 @@ namespace System.Numerics.Tests
|
||||||
return new BigInteger(Max(bytes1, bytes2).ToArray());
|
return new BigInteger(Max(bytes1, bytes2).ToArray());
|
||||||
case "b>>":
|
case "b>>":
|
||||||
return new BigInteger(ShiftLeft(bytes1, Negate(bytes2)).ToArray());
|
return new BigInteger(ShiftLeft(bytes1, Negate(bytes2)).ToArray());
|
||||||
|
case "b>>>":
|
||||||
|
return new BigInteger(ShiftRightUnsigned(bytes1, bytes2).ToArray());
|
||||||
case "b<<":
|
case "b<<":
|
||||||
return new BigInteger(ShiftLeft(bytes1, bytes2).ToArray());
|
return new BigInteger(ShiftLeft(bytes1, bytes2).ToArray());
|
||||||
|
case "bRotateLeft":
|
||||||
|
return new BigInteger(RotateLeft(bytes1, bytes2).ToArray());
|
||||||
|
case "bRotateRight":
|
||||||
|
return new BigInteger(RotateLeft(bytes1, Negate(bytes2)).ToArray());
|
||||||
case "b^":
|
case "b^":
|
||||||
return new BigInteger(Xor(bytes1, bytes2).ToArray());
|
return new BigInteger(Xor(bytes1, bytes2).ToArray());
|
||||||
case "b|":
|
case "b|":
|
||||||
|
@ -637,11 +643,68 @@ namespace System.Numerics.Tests
|
||||||
return bnew;
|
return bnew;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<byte> ShiftRightUnsigned(List<byte> bytes1, List<byte> bytes2)
|
||||||
|
{
|
||||||
|
int byteShift = (int)new BigInteger(Divide(Copy(bytes2), new List<byte>(new byte[] { 8 })).ToArray());
|
||||||
|
sbyte bitShift = (sbyte)new BigInteger(Remainder(Copy(bytes2), new List<byte>(new byte[] { 8 })).ToArray());
|
||||||
|
|
||||||
|
if (byteShift == 0 && bitShift == 0)
|
||||||
|
return bytes1;
|
||||||
|
|
||||||
|
if (byteShift < 0 || bitShift < 0)
|
||||||
|
return ShiftLeft(bytes1, Negate(bytes2));
|
||||||
|
|
||||||
|
Trim(bytes1);
|
||||||
|
|
||||||
|
byte fill = (bytes1[bytes1.Count - 1] & 0x80) != 0 ? byte.MaxValue : (byte)0;
|
||||||
|
|
||||||
|
if (fill == byte.MaxValue)
|
||||||
|
{
|
||||||
|
while (bytes1.Count % 4 != 0)
|
||||||
|
{
|
||||||
|
bytes1.Add(fill);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byteShift >= bytes1.Count)
|
||||||
|
{
|
||||||
|
return [fill];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fill == byte.MaxValue)
|
||||||
|
{
|
||||||
|
bytes1.Add(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < bitShift; i++)
|
||||||
|
{
|
||||||
|
bytes1 = ShiftRight(bytes1);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<byte> temp = new List<byte>();
|
||||||
|
for (int i = byteShift; i < bytes1.Count; i++)
|
||||||
|
{
|
||||||
|
temp.Add(bytes1[i]);
|
||||||
|
}
|
||||||
|
bytes1 = temp;
|
||||||
|
|
||||||
|
if (fill == byte.MaxValue && bytes1.Count % 4 == 1)
|
||||||
|
{
|
||||||
|
bytes1.RemoveAt(bytes1.Count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Trim(bytes1);
|
||||||
|
|
||||||
|
return bytes1;
|
||||||
|
}
|
||||||
|
|
||||||
public static List<byte> ShiftLeft(List<byte> bytes1, List<byte> bytes2)
|
public static List<byte> ShiftLeft(List<byte> bytes1, List<byte> bytes2)
|
||||||
{
|
{
|
||||||
int byteShift = (int)new BigInteger(Divide(Copy(bytes2), new List<byte>(new byte[] { 8 })).ToArray());
|
int byteShift = (int)new BigInteger(Divide(Copy(bytes2), new List<byte>(new byte[] { 8 })).ToArray());
|
||||||
sbyte bitShift = (sbyte)new BigInteger(Remainder(bytes2, new List<byte>(new byte[] { 8 })).ToArray());
|
sbyte bitShift = (sbyte)new BigInteger(Remainder(bytes2, new List<byte>(new byte[] { 8 })).ToArray());
|
||||||
|
|
||||||
|
Trim(bytes1);
|
||||||
|
|
||||||
for (int i = 0; i < Math.Abs(bitShift); i++)
|
for (int i = 0; i < Math.Abs(bitShift); i++)
|
||||||
{
|
{
|
||||||
if (bitShift < 0)
|
if (bitShift < 0)
|
||||||
|
@ -774,6 +837,105 @@ namespace System.Numerics.Tests
|
||||||
return bresult;
|
return bresult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<byte> RotateRight(List<byte> bytes)
|
||||||
|
{
|
||||||
|
List<byte> bresult = new List<byte>();
|
||||||
|
|
||||||
|
byte bottom = (byte)(bytes[0] & 0x01);
|
||||||
|
|
||||||
|
for (int i = 0; i < bytes.Count; i++)
|
||||||
|
{
|
||||||
|
byte newbyte = bytes[i];
|
||||||
|
|
||||||
|
newbyte = (byte)(newbyte / 2);
|
||||||
|
if ((i != (bytes.Count - 1)) && ((bytes[i + 1] & 0x01) == 1))
|
||||||
|
{
|
||||||
|
newbyte += 128;
|
||||||
|
}
|
||||||
|
if ((i == (bytes.Count - 1)) && (bottom != 0))
|
||||||
|
{
|
||||||
|
newbyte += 128;
|
||||||
|
}
|
||||||
|
bresult.Add(newbyte);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bresult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<byte> RotateLeft(List<byte> bytes)
|
||||||
|
{
|
||||||
|
List<byte> bresult = new List<byte>();
|
||||||
|
|
||||||
|
bool prevHead = (bytes[bytes.Count - 1] & 0x80) != 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < bytes.Count; i++)
|
||||||
|
{
|
||||||
|
byte newbyte = bytes[i];
|
||||||
|
|
||||||
|
newbyte = (byte)(newbyte * 2);
|
||||||
|
if (prevHead)
|
||||||
|
{
|
||||||
|
newbyte += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bresult.Add(newbyte);
|
||||||
|
|
||||||
|
prevHead = (bytes[i] & 0x80) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bresult;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static List<byte> RotateLeft(List<byte> bytes1, List<byte> bytes2)
|
||||||
|
{
|
||||||
|
List<byte> bytes1Copy = Copy(bytes1);
|
||||||
|
int byteShift = (int)new BigInteger(Divide(Copy(bytes2), new List<byte>(new byte[] { 8 })).ToArray());
|
||||||
|
sbyte bitShift = (sbyte)new BigInteger(Remainder(bytes2, new List<byte>(new byte[] { 8 })).ToArray());
|
||||||
|
|
||||||
|
Trim(bytes1);
|
||||||
|
|
||||||
|
byte fill = (bytes1[bytes1.Count - 1] & 0x80) != 0 ? byte.MaxValue : (byte)0;
|
||||||
|
|
||||||
|
if (fill == 0 && bytes1.Count > 1 && bytes1[bytes1.Count - 1] == 0)
|
||||||
|
bytes1.RemoveAt(bytes1.Count - 1);
|
||||||
|
|
||||||
|
while (bytes1.Count % 4 != 0)
|
||||||
|
{
|
||||||
|
bytes1.Add(fill);
|
||||||
|
}
|
||||||
|
|
||||||
|
byteShift %= bytes1.Count;
|
||||||
|
if (byteShift == 0 && bitShift == 0)
|
||||||
|
return bytes1Copy;
|
||||||
|
|
||||||
|
for (int i = 0; i < Math.Abs(bitShift); i++)
|
||||||
|
{
|
||||||
|
if (bitShift < 0)
|
||||||
|
{
|
||||||
|
bytes1 = RotateRight(bytes1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bytes1 = RotateLeft(bytes1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<byte> temp = new List<byte>();
|
||||||
|
for (int i = 0; i < bytes1.Count; i++)
|
||||||
|
{
|
||||||
|
temp.Add(bytes1[(i - byteShift + bytes1.Count) % bytes1.Count]);
|
||||||
|
}
|
||||||
|
bytes1 = temp;
|
||||||
|
|
||||||
|
if (fill == 0)
|
||||||
|
bytes1.Add(0);
|
||||||
|
|
||||||
|
Trim(bytes1);
|
||||||
|
|
||||||
|
return bytes1;
|
||||||
|
}
|
||||||
|
|
||||||
public static List<byte> SetLength(List<byte> bytes, int size)
|
public static List<byte> SetLength(List<byte> bytes, int size)
|
||||||
{
|
{
|
||||||
List<byte> bresult = new List<byte>();
|
List<byte> bresult = new List<byte>();
|
||||||
|
|
629
src/libraries/System.Runtime.Numerics/tests/BigInteger/Rotate.cs
Normal file
629
src/libraries/System.Runtime.Numerics/tests/BigInteger/Rotate.cs
Normal file
|
@ -0,0 +1,629 @@
|
||||||
|
// 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 abstract class RotateTestBase
|
||||||
|
{
|
||||||
|
public abstract string opstring { get; }
|
||||||
|
private static int s_samples = 10;
|
||||||
|
private static Random s_random = new Random(100);
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RunRotateTests()
|
||||||
|
{
|
||||||
|
byte[] tempByteArray1;
|
||||||
|
byte[] tempByteArray2;
|
||||||
|
|
||||||
|
// Rotate Method - Large BigIntegers - large + Shift
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomByteArray(s_random);
|
||||||
|
tempByteArray2 = GetRandomPosByteArray(s_random, 2);
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate Method - Large BigIntegers - small + Shift
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomByteArray(s_random);
|
||||||
|
tempByteArray2 = new byte[] { (byte)s_random.Next(1, 32) };
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate Method - Large BigIntegers - 32 bit Shift
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomByteArray(s_random);
|
||||||
|
tempByteArray2 = new byte[] { (byte)32 };
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate Method - All One Uint Large BigIntegers - 32 bit Shift
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomLengthAllOnesUIntByteArray(s_random);
|
||||||
|
tempByteArray2 = new byte[] { (byte)32 };
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate Method - Uint 0xffffffff 0x8000000 ... Large BigIntegers - 32 bit Shift
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomLengthFirstUIntMaxSecondUIntMSBMaxArray(s_random);
|
||||||
|
tempByteArray2 = new byte[] { (byte)32 };
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate Method - Large BigIntegers - large - Shift
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomByteArray(s_random);
|
||||||
|
tempByteArray2 = GetRandomNegByteArray(s_random, 2);
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate Method - Large BigIntegers - small - Shift
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomByteArray(s_random);
|
||||||
|
tempByteArray2 = new byte[] { unchecked((byte)s_random.Next(-31, 0)) };
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate Method - Large BigIntegers - -32 bit Shift
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomByteArray(s_random);
|
||||||
|
tempByteArray2 = new byte[] { (byte)0xe0 };
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate Method - Large BigIntegers - 0 bit Shift
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomByteArray(s_random);
|
||||||
|
tempByteArray2 = new byte[] { (byte)0 };
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate Method - Small BigIntegers - large + Shift
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
||||||
|
tempByteArray2 = GetRandomPosByteArray(s_random, 2);
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate Method - Small BigIntegers - small + Shift
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
||||||
|
tempByteArray2 = new byte[] { (byte)s_random.Next(1, 32) };
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate Method - Small BigIntegers - 32 bit Shift
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
||||||
|
tempByteArray2 = new byte[] { (byte)32 };
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
// Rotate Method - Small BigIntegers - large - Shift
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
||||||
|
tempByteArray2 = GetRandomNegByteArray(s_random, 2);
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate Method - Small BigIntegers - small - Shift
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
||||||
|
tempByteArray2 = new byte[] { unchecked((byte)s_random.Next(-31, 0)) };
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate Method - Small BigIntegers - -32 bit Shift
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
||||||
|
tempByteArray2 = new byte[] { (byte)0xe0 };
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate Method - Small BigIntegers - 0 bit Shift
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
||||||
|
tempByteArray2 = new byte[] { (byte)0 };
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate Method - Positive BigIntegers - Shift to 0
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomPosByteArray(s_random, 100);
|
||||||
|
tempByteArray2 = BitConverter.GetBytes(s_random.Next(8 * tempByteArray1.Length, 1000));
|
||||||
|
if (!BitConverter.IsLittleEndian)
|
||||||
|
{
|
||||||
|
Array.Reverse(tempByteArray2);
|
||||||
|
}
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate Method - Negative BigIntegers - Shift to -1
|
||||||
|
for (int i = 0; i < s_samples; i++)
|
||||||
|
{
|
||||||
|
tempByteArray1 = GetRandomNegByteArray(s_random, 100);
|
||||||
|
tempByteArray2 = BitConverter.GetBytes(s_random.Next(8 * tempByteArray1.Length, 1000));
|
||||||
|
if (!BitConverter.IsLittleEndian)
|
||||||
|
{
|
||||||
|
Array.Reverse(tempByteArray2);
|
||||||
|
}
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RunSmallTests()
|
||||||
|
{
|
||||||
|
foreach (int i in new int[] {
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
16,
|
||||||
|
31,
|
||||||
|
32,
|
||||||
|
33,
|
||||||
|
63,
|
||||||
|
64,
|
||||||
|
65,
|
||||||
|
100,
|
||||||
|
127,
|
||||||
|
128,
|
||||||
|
})
|
||||||
|
{
|
||||||
|
foreach (int shift in new int[] {
|
||||||
|
0,
|
||||||
|
-1, 1,
|
||||||
|
-16, 16,
|
||||||
|
-31, 31,
|
||||||
|
-32, 32,
|
||||||
|
-33, 33,
|
||||||
|
-63, 63,
|
||||||
|
-64, 64,
|
||||||
|
-65, 65,
|
||||||
|
-100, 100,
|
||||||
|
-127, 127,
|
||||||
|
-128, 128,
|
||||||
|
})
|
||||||
|
{
|
||||||
|
var num = Int128.One << i;
|
||||||
|
for (int k = -1; k <= 1; k++)
|
||||||
|
{
|
||||||
|
foreach (int sign in new int[] { -1, +1 })
|
||||||
|
{
|
||||||
|
Int128 value128 = sign * (num + k);
|
||||||
|
|
||||||
|
byte[] tempByteArray1 = GetRandomSmallByteArray(value128);
|
||||||
|
byte[] tempByteArray2 = GetRandomSmallByteArray(shift);
|
||||||
|
|
||||||
|
VerifyRotateString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void VerifyRotateString(string opstring)
|
||||||
|
{
|
||||||
|
StackCalc sc = new StackCalc(opstring);
|
||||||
|
while (sc.DoNextOperation())
|
||||||
|
{
|
||||||
|
Assert.Equal(sc.snCalc.Peek().ToString(), sc.myCalc.Peek().ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GetRandomSmallByteArray(Int128 num)
|
||||||
|
{
|
||||||
|
byte[] value = new byte[16];
|
||||||
|
|
||||||
|
for (int i = 0; i < value.Length; i++)
|
||||||
|
{
|
||||||
|
value[i] = (byte)num;
|
||||||
|
num >>= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GetRandomByteArray(Random random)
|
||||||
|
{
|
||||||
|
return GetRandomByteArray(random, random.Next(0, 1024));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GetRandomByteArray(Random random, int size)
|
||||||
|
{
|
||||||
|
return MyBigIntImp.GetRandomByteArray(random, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GetRandomPosByteArray(Random random, int size)
|
||||||
|
{
|
||||||
|
byte[] value = new byte[size];
|
||||||
|
|
||||||
|
for (int i = 0; i < value.Length; ++i)
|
||||||
|
{
|
||||||
|
value[i] = (byte)random.Next(0, 256);
|
||||||
|
}
|
||||||
|
value[value.Length - 1] &= 0x7F;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GetRandomNegByteArray(Random random, int size)
|
||||||
|
{
|
||||||
|
byte[] value = new byte[size];
|
||||||
|
|
||||||
|
for (int i = 0; i < value.Length; ++i)
|
||||||
|
{
|
||||||
|
value[i] = (byte)random.Next(0, 256);
|
||||||
|
}
|
||||||
|
value[value.Length - 1] |= 0x80;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GetRandomLengthAllOnesUIntByteArray(Random random)
|
||||||
|
{
|
||||||
|
int gap = random.Next(0, 128);
|
||||||
|
int byteLength = 4 + gap * 4 + 1;
|
||||||
|
byte[] array = new byte[byteLength];
|
||||||
|
array[0] = 1;
|
||||||
|
array[^1] = 0xFF;
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
private static byte[] GetRandomLengthFirstUIntMaxSecondUIntMSBMaxArray(Random random)
|
||||||
|
{
|
||||||
|
int gap = random.Next(0, 128);
|
||||||
|
int byteLength = 4 + gap * 4 + 1;
|
||||||
|
byte[] array = new byte[byteLength];
|
||||||
|
array[^5] = 0x80;
|
||||||
|
array[^1] = 0xFF;
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Print(byte[] bytes)
|
||||||
|
{
|
||||||
|
return MyBigIntImp.Print(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RotateLeftTest : RotateTestBase
|
||||||
|
{
|
||||||
|
public override string opstring => "bRotateLeft";
|
||||||
|
|
||||||
|
|
||||||
|
public static TheoryData<BigInteger, int, BigInteger> NegativeNumber_TestData = new TheoryData<BigInteger, int, BigInteger>
|
||||||
|
{
|
||||||
|
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0000)),
|
||||||
|
1,
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFE_0000_0001))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0000)),
|
||||||
|
2,
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFC_0000_0003))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0001)),
|
||||||
|
1,
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFE_0000_0003))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0001)),
|
||||||
|
2,
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFC_0000_0007))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0002)),
|
||||||
|
1,
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFE_0000_0005))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0002)),
|
||||||
|
2,
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFC_0000_000B))
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0x8000_0000_0000_0000)),
|
||||||
|
1,
|
||||||
|
new BigInteger(0x1)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0x8000_0000_0000_0000)),
|
||||||
|
2,
|
||||||
|
new BigInteger(0x2)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0x8000_0000_0000_0001)),
|
||||||
|
1,
|
||||||
|
new BigInteger(0x3)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0x8000_0000_0000_0001)),
|
||||||
|
2,
|
||||||
|
new BigInteger(0x6)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0x8000_0000_0000_0002)),
|
||||||
|
1,
|
||||||
|
new BigInteger(0x5)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0x8000_0000_0000_0002)),
|
||||||
|
2,
|
||||||
|
new BigInteger(0xA)
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
BigInteger.Parse("8000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
1,
|
||||||
|
new BigInteger(0x1)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("8000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
2,
|
||||||
|
new BigInteger(0x2)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("8000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
1,
|
||||||
|
new BigInteger(0x3)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("8000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
2,
|
||||||
|
new BigInteger(0x6)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("8000_0000_0000_0000_0000_0002".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
1,
|
||||||
|
new BigInteger(0x5)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("8000_0000_0000_0000_0000_0002".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
2,
|
||||||
|
new BigInteger(0xA)
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
BigInteger.Parse("________F_0000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
1,
|
||||||
|
BigInteger.Parse("________E_0000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("________F_0000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
2,
|
||||||
|
BigInteger.Parse("________C_0000_0000_0000_0000_0000_0003".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("________F_0000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
1,
|
||||||
|
BigInteger.Parse("________E_0000_0000_0000_0000_0000_0003".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("________F_0000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
2,
|
||||||
|
BigInteger.Parse("________C_0000_0000_0000_0000_0000_0007".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("________F_0000_0000_0000_0000_0000_0002".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
1,
|
||||||
|
BigInteger.Parse("________E_0000_0000_0000_0000_0000_0005".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("________F_0000_0000_0000_0000_0000_0002".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
2,
|
||||||
|
BigInteger.Parse("________C_0000_0000_0000_0000_0000_000B".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(NegativeNumber_TestData))]
|
||||||
|
public void NegativeNumber(BigInteger input, int rotateAmount, BigInteger expected)
|
||||||
|
{
|
||||||
|
Assert.Equal(expected, BigInteger.RotateLeft(input, rotateAmount));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void PowerOfTwo()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
foreach (int k in new int[] { 1, 2, 3, 10 })
|
||||||
|
{
|
||||||
|
BigInteger plus = BigInteger.One << (32 * k + i);
|
||||||
|
BigInteger minus = BigInteger.MinusOne << (32 * k + i);
|
||||||
|
|
||||||
|
Assert.Equal(BigInteger.One << (i == 31 ? 0 : (32 * k + i + 1)), BigInteger.RotateLeft(plus, 1));
|
||||||
|
Assert.Equal(BigInteger.One << i, BigInteger.RotateLeft(plus, 32));
|
||||||
|
Assert.Equal(BigInteger.One << (32 * (k - 1) + i), BigInteger.RotateLeft(plus, 32 * k));
|
||||||
|
|
||||||
|
Assert.Equal(i == 31 ? BigInteger.One : (new BigInteger(-1 << (i + 1)) << 32 * k) + 1,
|
||||||
|
BigInteger.RotateLeft(minus, 1));
|
||||||
|
Assert.Equal(new BigInteger(uint.MaxValue << i), BigInteger.RotateLeft(minus, 32));
|
||||||
|
Assert.Equal(new BigInteger(uint.MaxValue << i) << (32 * (k - 1)), BigInteger.RotateLeft(minus, 32 * k));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RotateRightTest : RotateTestBase
|
||||||
|
{
|
||||||
|
public override string opstring => "bRotateRight";
|
||||||
|
|
||||||
|
public static TheoryData<BigInteger, int, BigInteger> NegativeNumber_TestData = new TheoryData<BigInteger, int, BigInteger>
|
||||||
|
{
|
||||||
|
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0000)),
|
||||||
|
1,
|
||||||
|
new BigInteger(unchecked((long)0x7FFF_FFFF_8000_0000))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0000)),
|
||||||
|
2,
|
||||||
|
new BigInteger(unchecked((long)0x3FFF_FFFF_C000_0000))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0001)),
|
||||||
|
1,
|
||||||
|
new BigInteger(unchecked((int)0x8000_0000))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0001)),
|
||||||
|
2,
|
||||||
|
new BigInteger(unchecked((long)0x7FFF_FFFF_C000_0000))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0002)),
|
||||||
|
1,
|
||||||
|
new BigInteger(unchecked((long)0x7FFF_FFFF_8000_0001))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0xFFFF_FFFF_0000_0002)),
|
||||||
|
2,
|
||||||
|
new BigInteger(unchecked((long)0xBFFF_FFFF_C000_0000))
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0x8000_0000_0000_0000)),
|
||||||
|
1,
|
||||||
|
new BigInteger(unchecked((long)0x4000_0000_0000_0000))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0x8000_0000_0000_0000)),
|
||||||
|
2,
|
||||||
|
new BigInteger(unchecked((long)0x2000_0000_0000_0000))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0x8000_0000_0000_0001)),
|
||||||
|
1,
|
||||||
|
new BigInteger(unchecked((long)0xC000_0000_0000_0000))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0x8000_0000_0000_0001)),
|
||||||
|
2,
|
||||||
|
new BigInteger(unchecked((long)0x6000_0000_0000_0000))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0x8000_0000_0000_0002)),
|
||||||
|
1,
|
||||||
|
new BigInteger(unchecked((long)0x4000_0000_0000_0001))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new BigInteger(unchecked((long)0x8000_0000_0000_0002)),
|
||||||
|
2,
|
||||||
|
new BigInteger(unchecked((long)0xA000_0000_0000_0000))
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
BigInteger.Parse("8000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
1,
|
||||||
|
BigInteger.Parse("4000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("8000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
2,
|
||||||
|
BigInteger.Parse("2000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("8000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
1,
|
||||||
|
BigInteger.Parse("C000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("8000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
2,
|
||||||
|
BigInteger.Parse("6000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("8000_0000_0000_0000_0000_0002".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
1,
|
||||||
|
BigInteger.Parse("4000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("8000_0000_0000_0000_0000_0002".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
2,
|
||||||
|
BigInteger.Parse("A000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
BigInteger.Parse("________F_0000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
1,
|
||||||
|
BigInteger.Parse("7FFF_FFFF_8000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("________F_0000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
2,
|
||||||
|
BigInteger.Parse("3FFF_FFFF_C000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("________F_0000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
1,
|
||||||
|
BigInteger.Parse("__________8000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("________F_0000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
2,
|
||||||
|
BigInteger.Parse("7FFF_FFFF_C000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("________F_0000_0000_0000_0000_0000_0002".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
1,
|
||||||
|
BigInteger.Parse("7FFF_FFFF_8000_0000_0000_0000_0000_0001".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BigInteger.Parse("________F_0000_0000_0000_0000_0000_0002".Replace("_", ""), NumberStyles.HexNumber),
|
||||||
|
2,
|
||||||
|
BigInteger.Parse("BFFF_FFFF_C000_0000_0000_0000_0000_0000".Replace("_", ""), NumberStyles.HexNumber)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(NegativeNumber_TestData))]
|
||||||
|
public void NegativeNumber(BigInteger input, int rotateAmount, BigInteger expected)
|
||||||
|
{
|
||||||
|
Assert.Equal(expected, BigInteger.RotateRight(input, rotateAmount));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void PowerOfTwo()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
foreach (int k in new int[] { 1, 2, 3, 10 })
|
||||||
|
{
|
||||||
|
BigInteger plus = BigInteger.One << (32 * k + i);
|
||||||
|
BigInteger minus = BigInteger.MinusOne << (32 * k + i);
|
||||||
|
|
||||||
|
Assert.Equal(BigInteger.One << (32 * k + i - 1), BigInteger.RotateRight(plus, 1));
|
||||||
|
Assert.Equal(BigInteger.One << (32 * (k - 1) + i), BigInteger.RotateRight(plus, 32));
|
||||||
|
Assert.Equal(BigInteger.One << i, BigInteger.RotateRight(plus, 32 * k));
|
||||||
|
|
||||||
|
Assert.Equal(new BigInteger(uint.MaxValue << i) << (32 * k - 1), BigInteger.RotateRight(minus, 1));
|
||||||
|
Assert.Equal(new BigInteger(uint.MaxValue << i) << (32 * (k - 1)), BigInteger.RotateRight(minus, 32));
|
||||||
|
Assert.Equal(new BigInteger(uint.MaxValue << i), BigInteger.RotateRight(minus, 32 * k));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
// Licensed to the .NET Foundation under one or more agreements.
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace System.Numerics.Tests
|
namespace System.Numerics.Tests
|
||||||
|
@ -151,6 +152,56 @@ namespace System.Numerics.Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RunSmallTests()
|
||||||
|
{
|
||||||
|
foreach (int i in new int[] {
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
16,
|
||||||
|
31,
|
||||||
|
32,
|
||||||
|
33,
|
||||||
|
63,
|
||||||
|
64,
|
||||||
|
65,
|
||||||
|
100,
|
||||||
|
127,
|
||||||
|
128,
|
||||||
|
})
|
||||||
|
{
|
||||||
|
foreach (int shift in new int[] {
|
||||||
|
0,
|
||||||
|
-1, 1,
|
||||||
|
-16, 16,
|
||||||
|
-31, 31,
|
||||||
|
-32, 32,
|
||||||
|
-33, 33,
|
||||||
|
-63, 63,
|
||||||
|
-64, 64,
|
||||||
|
-65, 65,
|
||||||
|
-100, 100,
|
||||||
|
-127, 127,
|
||||||
|
-128, 128,
|
||||||
|
})
|
||||||
|
{
|
||||||
|
var num = Int128.One << i;
|
||||||
|
for (int k = -1; k <= 1; k++)
|
||||||
|
{
|
||||||
|
foreach (int sign in new int[] { -1, +1 })
|
||||||
|
{
|
||||||
|
Int128 value128 = sign * (num + k);
|
||||||
|
|
||||||
|
byte[] tempByteArray1 = GetRandomSmallByteArray(value128);
|
||||||
|
byte[] tempByteArray2 = GetRandomSmallByteArray(shift);
|
||||||
|
|
||||||
|
VerifyLeftShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b<<");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void VerifyLeftShiftString(string opstring)
|
private static void VerifyLeftShiftString(string opstring)
|
||||||
{
|
{
|
||||||
StackCalc sc = new StackCalc(opstring);
|
StackCalc sc = new StackCalc(opstring);
|
||||||
|
@ -160,6 +211,19 @@ namespace System.Numerics.Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static byte[] GetRandomSmallByteArray(Int128 num)
|
||||||
|
{
|
||||||
|
byte[] value = new byte[16];
|
||||||
|
|
||||||
|
for (int i = 0; i < value.Length; i++)
|
||||||
|
{
|
||||||
|
value[i] = (byte)num;
|
||||||
|
num >>= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
private static byte[] GetRandomByteArray(Random random)
|
private static byte[] GetRandomByteArray(Random random)
|
||||||
{
|
{
|
||||||
return GetRandomByteArray(random, random.Next(0, 1024));
|
return GetRandomByteArray(random, random.Next(0, 1024));
|
||||||
|
|
|
@ -1,92 +1,29 @@
|
||||||
// Licensed to the .NET Foundation under one or more agreements.
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace System.Numerics.Tests
|
namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
public class op_rightshiftTest
|
public abstract class op_rightshiftTestBase
|
||||||
{
|
{
|
||||||
|
public abstract string opstring { get; }
|
||||||
private static int s_samples = 10;
|
private static int s_samples = 10;
|
||||||
private static Random s_random = new Random(100);
|
private static Random s_random = new Random(100);
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void BigShiftsTest()
|
public void RunRightShiftTests()
|
||||||
{
|
{
|
||||||
BigInteger a = new BigInteger(1);
|
byte[] tempByteArray1;
|
||||||
BigInteger b = new BigInteger(Math.Pow(2, 31));
|
byte[] tempByteArray2;
|
||||||
|
|
||||||
for (int i = 0; i < 100; i++)
|
|
||||||
{
|
|
||||||
BigInteger a1 = (a << (i + 31));
|
|
||||||
BigInteger a2 = a1 >> i;
|
|
||||||
|
|
||||||
Assert.Equal(b, a2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] // May fail on 32-bit due to a large memory requirement
|
|
||||||
public static void LargeNegativeBigIntegerShiftTest()
|
|
||||||
{
|
|
||||||
// Create a very large negative BigInteger
|
|
||||||
int bitsPerElement = 8 * sizeof(uint);
|
|
||||||
int maxBitLength = ((Array.MaxLength / bitsPerElement) * bitsPerElement);
|
|
||||||
BigInteger bigInt = new BigInteger(-1) << (maxBitLength - 1);
|
|
||||||
Assert.Equal(maxBitLength - 1, bigInt.GetBitLength());
|
|
||||||
Assert.Equal(-1, bigInt.Sign);
|
|
||||||
|
|
||||||
// Validate internal representation.
|
|
||||||
// At this point, bigInt should be a 1 followed by maxBitLength - 1 zeros.
|
|
||||||
// Given this, bigInt._bits is expected to be structured as follows:
|
|
||||||
// - _bits.Length == ceil(maxBitLength / bitsPerElement)
|
|
||||||
// - First (_bits.Length - 1) elements: 0x00000000
|
|
||||||
// - Last element: 0x80000000
|
|
||||||
// ^------ (There's the leading '1')
|
|
||||||
|
|
||||||
Assert.Equal((maxBitLength + (bitsPerElement - 1)) / bitsPerElement, bigInt._bits.Length);
|
|
||||||
|
|
||||||
uint i = 0;
|
|
||||||
for (; i < (bigInt._bits.Length - 1); i++) {
|
|
||||||
Assert.Equal(0x00000000u, bigInt._bits[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.Equal(0x80000000u, bigInt._bits[i]);
|
|
||||||
|
|
||||||
// Right shift the BigInteger
|
|
||||||
BigInteger shiftedBigInt = bigInt >> 1;
|
|
||||||
Assert.Equal(maxBitLength - 2, shiftedBigInt.GetBitLength());
|
|
||||||
Assert.Equal(-1, shiftedBigInt.Sign);
|
|
||||||
|
|
||||||
// Validate internal representation.
|
|
||||||
// At this point, shiftedBigInt should be a 1 followed by maxBitLength - 2 zeros.
|
|
||||||
// Given this, shiftedBigInt._bits is expected to be structured as follows:
|
|
||||||
// - _bits.Length == ceil((maxBitLength - 1) / bitsPerElement)
|
|
||||||
// - First (_bits.Length - 1) elements: 0x00000000
|
|
||||||
// - Last element: 0x40000000
|
|
||||||
// ^------ (the '1' is now one position to the right)
|
|
||||||
|
|
||||||
Assert.Equal(((maxBitLength - 1) + (bitsPerElement - 1)) / bitsPerElement, shiftedBigInt._bits.Length);
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
for (; i < (shiftedBigInt._bits.Length - 1); i++) {
|
|
||||||
Assert.Equal(0x00000000u, shiftedBigInt._bits[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.Equal(0x40000000u, shiftedBigInt._bits[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public static void RunRightShiftTests()
|
|
||||||
{
|
|
||||||
byte[] tempByteArray1 = new byte[0];
|
|
||||||
byte[] tempByteArray2 = new byte[0];
|
|
||||||
|
|
||||||
// RightShift Method - Large BigIntegers - large + Shift
|
// RightShift Method - Large BigIntegers - large + Shift
|
||||||
for (int i = 0; i < s_samples; i++)
|
for (int i = 0; i < s_samples; i++)
|
||||||
{
|
{
|
||||||
tempByteArray1 = GetRandomByteArray(s_random);
|
tempByteArray1 = GetRandomByteArray(s_random);
|
||||||
tempByteArray2 = GetRandomPosByteArray(s_random, 2);
|
tempByteArray2 = GetRandomPosByteArray(s_random, 2);
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightShift Method - Large BigIntegers - small + Shift
|
// RightShift Method - Large BigIntegers - small + Shift
|
||||||
|
@ -94,7 +31,7 @@ namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
tempByteArray1 = GetRandomByteArray(s_random);
|
tempByteArray1 = GetRandomByteArray(s_random);
|
||||||
tempByteArray2 = new byte[] { (byte)s_random.Next(1, 32) };
|
tempByteArray2 = new byte[] { (byte)s_random.Next(1, 32) };
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightShift Method - Large BigIntegers - 32 bit Shift
|
// RightShift Method - Large BigIntegers - 32 bit Shift
|
||||||
|
@ -102,7 +39,7 @@ namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
tempByteArray1 = GetRandomByteArray(s_random);
|
tempByteArray1 = GetRandomByteArray(s_random);
|
||||||
tempByteArray2 = new byte[] { (byte)32 };
|
tempByteArray2 = new byte[] { (byte)32 };
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightShift Method - All One Uint Large BigIntegers - 32 bit Shift
|
// RightShift Method - All One Uint Large BigIntegers - 32 bit Shift
|
||||||
|
@ -110,7 +47,7 @@ namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
tempByteArray1 = GetRandomLengthAllOnesUIntByteArray(s_random);
|
tempByteArray1 = GetRandomLengthAllOnesUIntByteArray(s_random);
|
||||||
tempByteArray2 = new byte[] { (byte)32 };
|
tempByteArray2 = new byte[] { (byte)32 };
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightShift Method - Uint 0xffffffff 0x8000000 ... Large BigIntegers - 32 bit Shift
|
// RightShift Method - Uint 0xffffffff 0x8000000 ... Large BigIntegers - 32 bit Shift
|
||||||
|
@ -118,7 +55,7 @@ namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
tempByteArray1 = GetRandomLengthFirstUIntMaxSecondUIntMSBMaxArray(s_random);
|
tempByteArray1 = GetRandomLengthFirstUIntMaxSecondUIntMSBMaxArray(s_random);
|
||||||
tempByteArray2 = new byte[] { (byte)32 };
|
tempByteArray2 = new byte[] { (byte)32 };
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightShift Method - Large BigIntegers - large - Shift
|
// RightShift Method - Large BigIntegers - large - Shift
|
||||||
|
@ -126,7 +63,7 @@ namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
tempByteArray1 = GetRandomByteArray(s_random);
|
tempByteArray1 = GetRandomByteArray(s_random);
|
||||||
tempByteArray2 = GetRandomNegByteArray(s_random, 2);
|
tempByteArray2 = GetRandomNegByteArray(s_random, 2);
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightShift Method - Large BigIntegers - small - Shift
|
// RightShift Method - Large BigIntegers - small - Shift
|
||||||
|
@ -134,7 +71,7 @@ namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
tempByteArray1 = GetRandomByteArray(s_random);
|
tempByteArray1 = GetRandomByteArray(s_random);
|
||||||
tempByteArray2 = new byte[] { unchecked((byte)s_random.Next(-31, 0)) };
|
tempByteArray2 = new byte[] { unchecked((byte)s_random.Next(-31, 0)) };
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightShift Method - Large BigIntegers - -32 bit Shift
|
// RightShift Method - Large BigIntegers - -32 bit Shift
|
||||||
|
@ -142,7 +79,7 @@ namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
tempByteArray1 = GetRandomByteArray(s_random);
|
tempByteArray1 = GetRandomByteArray(s_random);
|
||||||
tempByteArray2 = new byte[] { (byte)0xe0 };
|
tempByteArray2 = new byte[] { (byte)0xe0 };
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightShift Method - Large BigIntegers - 0 bit Shift
|
// RightShift Method - Large BigIntegers - 0 bit Shift
|
||||||
|
@ -150,7 +87,7 @@ namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
tempByteArray1 = GetRandomByteArray(s_random);
|
tempByteArray1 = GetRandomByteArray(s_random);
|
||||||
tempByteArray2 = new byte[] { (byte)0 };
|
tempByteArray2 = new byte[] { (byte)0 };
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightShift Method - Small BigIntegers - large + Shift
|
// RightShift Method - Small BigIntegers - large + Shift
|
||||||
|
@ -158,7 +95,7 @@ namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
||||||
tempByteArray2 = GetRandomPosByteArray(s_random, 2);
|
tempByteArray2 = GetRandomPosByteArray(s_random, 2);
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightShift Method - Small BigIntegers - small + Shift
|
// RightShift Method - Small BigIntegers - small + Shift
|
||||||
|
@ -166,7 +103,7 @@ namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
||||||
tempByteArray2 = new byte[] { (byte)s_random.Next(1, 32) };
|
tempByteArray2 = new byte[] { (byte)s_random.Next(1, 32) };
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightShift Method - Small BigIntegers - 32 bit Shift
|
// RightShift Method - Small BigIntegers - 32 bit Shift
|
||||||
|
@ -174,14 +111,14 @@ namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
||||||
tempByteArray2 = new byte[] { (byte)32 };
|
tempByteArray2 = new byte[] { (byte)32 };
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
// RightShift Method - Small BigIntegers - large - Shift
|
// RightShift Method - Small BigIntegers - large - Shift
|
||||||
for (int i = 0; i < s_samples; i++)
|
for (int i = 0; i < s_samples; i++)
|
||||||
{
|
{
|
||||||
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
||||||
tempByteArray2 = GetRandomNegByteArray(s_random, 2);
|
tempByteArray2 = GetRandomNegByteArray(s_random, 2);
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightShift Method - Small BigIntegers - small - Shift
|
// RightShift Method - Small BigIntegers - small - Shift
|
||||||
|
@ -189,7 +126,7 @@ namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
||||||
tempByteArray2 = new byte[] { unchecked((byte)s_random.Next(-31, 0)) };
|
tempByteArray2 = new byte[] { unchecked((byte)s_random.Next(-31, 0)) };
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightShift Method - Small BigIntegers - -32 bit Shift
|
// RightShift Method - Small BigIntegers - -32 bit Shift
|
||||||
|
@ -197,7 +134,7 @@ namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
||||||
tempByteArray2 = new byte[] { (byte)0xe0 };
|
tempByteArray2 = new byte[] { (byte)0xe0 };
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightShift Method - Small BigIntegers - 0 bit Shift
|
// RightShift Method - Small BigIntegers - 0 bit Shift
|
||||||
|
@ -205,7 +142,7 @@ namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
tempByteArray1 = GetRandomByteArray(s_random, 2);
|
||||||
tempByteArray2 = new byte[] { (byte)0 };
|
tempByteArray2 = new byte[] { (byte)0 };
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightShift Method - Positive BigIntegers - Shift to 0
|
// RightShift Method - Positive BigIntegers - Shift to 0
|
||||||
|
@ -217,7 +154,7 @@ namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
Array.Reverse(tempByteArray2);
|
Array.Reverse(tempByteArray2);
|
||||||
}
|
}
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RightShift Method - Negative BigIntegers - Shift to -1
|
// RightShift Method - Negative BigIntegers - Shift to -1
|
||||||
|
@ -229,7 +166,57 @@ namespace System.Numerics.Tests
|
||||||
{
|
{
|
||||||
Array.Reverse(tempByteArray2);
|
Array.Reverse(tempByteArray2);
|
||||||
}
|
}
|
||||||
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RunSmallTests()
|
||||||
|
{
|
||||||
|
foreach (int i in new int[] {
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
16,
|
||||||
|
31,
|
||||||
|
32,
|
||||||
|
33,
|
||||||
|
63,
|
||||||
|
64,
|
||||||
|
65,
|
||||||
|
100,
|
||||||
|
127,
|
||||||
|
128,
|
||||||
|
})
|
||||||
|
{
|
||||||
|
foreach (int shift in new int[] {
|
||||||
|
0,
|
||||||
|
-1, 1,
|
||||||
|
-16, 16,
|
||||||
|
-31, 31,
|
||||||
|
-32, 32,
|
||||||
|
-33, 33,
|
||||||
|
-63, 63,
|
||||||
|
-64, 64,
|
||||||
|
-65, 65,
|
||||||
|
-100, 100,
|
||||||
|
-127, 127,
|
||||||
|
-128, 128,
|
||||||
|
})
|
||||||
|
{
|
||||||
|
var num = Int128.One << i;
|
||||||
|
for (int k = -1; k <= 1; k++)
|
||||||
|
{
|
||||||
|
foreach (int sign in new int[] { -1, +1 })
|
||||||
|
{
|
||||||
|
Int128 value128 = sign * (num + k);
|
||||||
|
|
||||||
|
byte[] tempByteArray1 = GetRandomSmallByteArray(value128);
|
||||||
|
byte[] tempByteArray2 = GetRandomSmallByteArray(shift);
|
||||||
|
|
||||||
|
VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + opstring);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,6 +229,19 @@ namespace System.Numerics.Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static byte[] GetRandomSmallByteArray(Int128 num)
|
||||||
|
{
|
||||||
|
byte[] value = new byte[16];
|
||||||
|
|
||||||
|
for (int i = 0; i < value.Length; i++)
|
||||||
|
{
|
||||||
|
value[i] = (byte)num;
|
||||||
|
num >>= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
private static byte[] GetRandomByteArray(Random random)
|
private static byte[] GetRandomByteArray(Random random)
|
||||||
{
|
{
|
||||||
return GetRandomByteArray(random, random.Next(0, 1024));
|
return GetRandomByteArray(random, random.Next(0, 1024));
|
||||||
|
@ -292,7 +292,7 @@ namespace System.Numerics.Tests
|
||||||
int gap = random.Next(0, 128);
|
int gap = random.Next(0, 128);
|
||||||
int byteLength = 4 + gap * 4 + 1;
|
int byteLength = 4 + gap * 4 + 1;
|
||||||
byte[] array = new byte[byteLength];
|
byte[] array = new byte[byteLength];
|
||||||
array[^6] = 0x80;
|
array[^5] = 0x80;
|
||||||
array[^1] = 0xFF;
|
array[^1] = 0xFF;
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
@ -302,4 +302,93 @@ namespace System.Numerics.Tests
|
||||||
return MyBigIntImp.Print(bytes);
|
return MyBigIntImp.Print(bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public class op_rightshiftTest : op_rightshiftTestBase
|
||||||
|
{
|
||||||
|
public override string opstring => "b>>";
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public static void BigShiftsTest()
|
||||||
|
{
|
||||||
|
BigInteger a = new BigInteger(1);
|
||||||
|
BigInteger b = new BigInteger(Math.Pow(2, 31));
|
||||||
|
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
BigInteger a1 = (a << (i + 31));
|
||||||
|
BigInteger a2 = a1 >> i;
|
||||||
|
|
||||||
|
Assert.Equal(b, a2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] // May fail on 32-bit due to a large memory requirement
|
||||||
|
public static void LargeNegativeBigIntegerShiftTest()
|
||||||
|
{
|
||||||
|
// Create a very large negative BigInteger
|
||||||
|
int bitsPerElement = 8 * sizeof(uint);
|
||||||
|
int maxBitLength = ((Array.MaxLength / bitsPerElement) * bitsPerElement);
|
||||||
|
BigInteger bigInt = new BigInteger(-1) << (maxBitLength - 1);
|
||||||
|
Assert.Equal(maxBitLength - 1, bigInt.GetBitLength());
|
||||||
|
Assert.Equal(-1, bigInt.Sign);
|
||||||
|
|
||||||
|
// Validate internal representation.
|
||||||
|
// At this point, bigInt should be a 1 followed by maxBitLength - 1 zeros.
|
||||||
|
// Given this, bigInt._bits is expected to be structured as follows:
|
||||||
|
// - _bits.Length == ceil(maxBitLength / bitsPerElement)
|
||||||
|
// - First (_bits.Length - 1) elements: 0x00000000
|
||||||
|
// - Last element: 0x80000000
|
||||||
|
// ^------ (There's the leading '1')
|
||||||
|
|
||||||
|
Assert.Equal((maxBitLength + (bitsPerElement - 1)) / bitsPerElement, bigInt._bits.Length);
|
||||||
|
|
||||||
|
uint i = 0;
|
||||||
|
for (; i < (bigInt._bits.Length - 1); i++)
|
||||||
|
{
|
||||||
|
Assert.Equal(0x00000000u, bigInt._bits[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.Equal(0x80000000u, bigInt._bits[i]);
|
||||||
|
|
||||||
|
// Right shift the BigInteger
|
||||||
|
BigInteger shiftedBigInt = bigInt >> 1;
|
||||||
|
Assert.Equal(maxBitLength - 2, shiftedBigInt.GetBitLength());
|
||||||
|
Assert.Equal(-1, shiftedBigInt.Sign);
|
||||||
|
|
||||||
|
// Validate internal representation.
|
||||||
|
// At this point, shiftedBigInt should be a 1 followed by maxBitLength - 2 zeros.
|
||||||
|
// Given this, shiftedBigInt._bits is expected to be structured as follows:
|
||||||
|
// - _bits.Length == ceil((maxBitLength - 1) / bitsPerElement)
|
||||||
|
// - First (_bits.Length - 1) elements: 0x00000000
|
||||||
|
// - Last element: 0x40000000
|
||||||
|
// ^------ (the '1' is now one position to the right)
|
||||||
|
|
||||||
|
Assert.Equal(((maxBitLength - 1) + (bitsPerElement - 1)) / bitsPerElement, shiftedBigInt._bits.Length);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
for (; i < (shiftedBigInt._bits.Length - 1); i++)
|
||||||
|
{
|
||||||
|
Assert.Equal(0x00000000u, shiftedBigInt._bits[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.Equal(0x40000000u, shiftedBigInt._bits[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class op_UnsignedRightshiftTest : op_rightshiftTestBase
|
||||||
|
{
|
||||||
|
public override string opstring => "b>>>";
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void PowerOfTwo()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
foreach (int k in new int[] { 1, 2, 10 })
|
||||||
|
{
|
||||||
|
Assert.Equal(BigInteger.One << i, (BigInteger.One << (32 * k + i)) >>> (32 * k));
|
||||||
|
Assert.Equal(new BigInteger(unchecked((int)(uint.MaxValue << i))), (BigInteger.MinusOne << (32 * k + i)) >>> (32 * k));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,8 +191,14 @@ namespace System.Numerics.Tests
|
||||||
return BigInteger.Max(num1, num2);
|
return BigInteger.Max(num1, num2);
|
||||||
case "b>>":
|
case "b>>":
|
||||||
return num1 >> (int)num2;
|
return num1 >> (int)num2;
|
||||||
|
case "b>>>":
|
||||||
|
return num1 >>> (int)num2;
|
||||||
case "b<<":
|
case "b<<":
|
||||||
return num1 << (int)num2;
|
return num1 << (int)num2;
|
||||||
|
case "bRotateLeft":
|
||||||
|
return BigInteger.RotateLeft(num1, (int)num2);
|
||||||
|
case "bRotateRight":
|
||||||
|
return BigInteger.RotateRight(num1, (int)num2);
|
||||||
case "b^":
|
case "b^":
|
||||||
return num1 ^ num2;
|
return num1 ^ num2;
|
||||||
case "b|":
|
case "b|":
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
<Compile Include="BigInteger\op_multiply.cs" />
|
<Compile Include="BigInteger\op_multiply.cs" />
|
||||||
<Compile Include="BigInteger\op_not.cs" />
|
<Compile Include="BigInteger\op_not.cs" />
|
||||||
<Compile Include="BigInteger\op_or.cs" />
|
<Compile Include="BigInteger\op_or.cs" />
|
||||||
|
<Compile Include="BigInteger\Rotate.cs" />
|
||||||
<Compile Include="BigInteger\op_rightshift.cs" />
|
<Compile Include="BigInteger\op_rightshift.cs" />
|
||||||
<Compile Include="BigInteger\op_xor.cs" />
|
<Compile Include="BigInteger\op_xor.cs" />
|
||||||
<Compile Include="BigInteger\parse.cs" />
|
<Compile Include="BigInteger\parse.cs" />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue