Skip to content
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
d65a4db
Fixed Random Factory
cschuchardt88 Aug 22, 2025
b987d14
Merge branch 'dev' into dev/fix/random
Jim8y Aug 24, 2025
2c53ff9
Merge branch 'dev' into dev/fix/random
Jim8y Aug 26, 2025
57427d6
Merge branch 'dev' into dev/fix/random
Wi1l-B0t Aug 26, 2025
6609aa8
Merge branch 'dev' into dev/fix/random
cschuchardt88 Aug 27, 2025
f62ad9a
Check Zero
cschuchardt88 Aug 29, 2025
fc405e7
fixed tests
cschuchardt88 Aug 29, 2025
1234952
fix test
cschuchardt88 Aug 29, 2025
9325066
Merge branch 'dev' into dev/fix/random
cschuchardt88 Aug 30, 2025
683e548
Merge branch 'dev' into dev/fix/random
cschuchardt88 Sep 8, 2025
6771a19
Changed function to work the same way was stdlib call
cschuchardt88 Sep 15, 2025
a4cea2c
Merge branch 'dev' into dev/fix/random
cschuchardt88 Sep 15, 2025
97c2188
Fixed unit tests
cschuchardt88 Sep 15, 2025
204e0f8
Merge branch 'dev' into dev/fix/random
ajara87 Sep 16, 2025
267063b
renamed variables
cschuchardt88 Sep 20, 2025
fe88dc1
Fixed threshold
cschuchardt88 Sep 20, 2025
8cb2e3c
optimized
cschuchardt88 Sep 21, 2025
2c02f16
Merge branch 'dev' into dev/fix/random
cschuchardt88 Sep 21, 2025
33e7289
Fixed bug
cschuchardt88 Sep 21, 2025
47fd91f
Fixed another bug for signed integer
cschuchardt88 Sep 21, 2025
442c17b
Merge branch 'dev/fix/random' of github.com:cschuchardt88/neo into de…
cschuchardt88 Sep 21, 2025
d085029
Fixed bug
cschuchardt88 Sep 22, 2025
e7f7495
make maxvalue const
cschuchardt88 Sep 23, 2025
9447b4e
Make `NextBigInteger` dynamic based off the maxvalue
cschuchardt88 Sep 23, 2025
fbc58ba
removed un-needed test
cschuchardt88 Sep 23, 2025
89f21f5
Fixed `2^L` values in `NextInteger` for `RandomNumberFactory`
cschuchardt88 Sep 25, 2025
fb32c23
Merge branch 'dev' into dev/fix/random
Wi1l-B0t Sep 25, 2025
8dacd62
Merge branch 'dev' into dev/fix/random
cschuchardt88 Oct 5, 2025
c0cb5bb
Fixed the tests for `RandomNumberFactory`
cschuchardt88 Oct 6, 2025
92bdb8f
Merge branch 'dev' into dev/fix/random
cschuchardt88 Oct 10, 2025
76705cf
Merge branch 'dev' into dev/fix/random
cschuchardt88 Oct 11, 2025
0515f40
Merge branch 'dev' into dev/fix/random
NGDAdmin Oct 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions src/Neo.Extensions/BigIntegerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,6 @@ public static BigInteger Sqrt(this BigInteger value)
return z;
}

internal static BigInteger GetLowPart(this BigInteger value, int bitCount)
{
var mask = (BigInteger.One << bitCount) - 1;
return value & mask;
}

/// <summary>
/// Gets the number of bits required for shortest two's complement representation of the current instance without the sign bit.
/// Note: This method is imprecise and might not work as expected with integers larger than 256 bits if less than .NET5.
Expand Down
52 changes: 11 additions & 41 deletions src/Neo.Extensions/Factories/RandomNumberFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,15 +176,15 @@ public static ulong NextUInt64()

public static ulong NextUInt64(ulong maxValue)
{
var randomProduct = BigMul(maxValue, NextUInt64(), out var lowPart);
var randomProduct = Math.BigMul(maxValue, NextUInt64(), out var lowPart);

if (lowPart < maxValue)
{
var remainder = (0ul - maxValue) % maxValue;

while (lowPart < remainder)
{
randomProduct = BigMul(maxValue, NextUInt64(), out lowPart);
randomProduct = Math.BigMul(maxValue, NextUInt64(), out lowPart);
}
}

Expand Down Expand Up @@ -216,34 +216,27 @@ public static BigInteger NextBigInteger(BigInteger maxValue)
if (maxValue.Sign < 0)
throw new ArgumentOutOfRangeException(nameof(maxValue));

if (maxValue == 0 || maxValue == 1)
return BigInteger.Zero;

var maxValueBits = maxValue.GetByteCount() * 8;
var maxValueSize = BigInteger.Pow(2, maxValueBits);
var maxMaxValue = BigInteger.One << maxValueBits;

var randomProduct = maxValue * NextBigInteger(maxValueBits);
var randomProductBits = randomProduct.GetByteCount() * 8;

var lowPart = randomProduct.GetLowPart(maxValueBits);
var lowPart = randomProduct % maxMaxValue;

if (lowPart < maxValue)
{
var remainder = (maxValueSize - maxValue) % maxValue;
var threshold = (maxMaxValue - maxValue) % maxValue;

while (lowPart < remainder)
while (lowPart < threshold)
{
randomProduct = maxValue * NextBigInteger(maxValueBits);
randomProductBits = randomProduct.GetByteCount() * 8;
lowPart = randomProduct.GetLowPart(maxValueBits);
lowPart = randomProduct % maxMaxValue;
}
}

var result = randomProduct >> (randomProductBits - maxValueBits);

// Since BigInteger doesn't have a max value or bit size
// anything over 'maxValue' return zero
if (result >= maxValue)
return BigInteger.Zero;

return result;
return randomProduct >> maxValueBits;
}

public static BigInteger NextBigInteger(int sizeInBits)
Expand All @@ -264,28 +257,5 @@ public static BigInteger NextBigInteger(int sizeInBits)

return new BigInteger(b);
}

private static ulong BigMul(ulong a, ulong b, out ulong low)
{
// Adaptation of algorithm for multiplication
// of 32-bit unsigned integers described
// in Hacker's Delight by Henry S. Warren, Jr. (ISBN 0-201-91465-4), Chapter 8
// Basically, it's an optimized version of FOIL method applied to
// low and high dwords of each operand

// Use 32-bit uints to optimize the fallback for 32-bit platforms.
var al = (uint)a;
var ah = (uint)(a >> 32);
var bl = (uint)b;
var bh = (uint)(b >> 32);

var mull = ((ulong)al) * bl;
var t = ((ulong)ah) * bl + (mull >> 32);
var tl = ((ulong)al) * bh + (uint)t;

low = (tl << 32) | (uint)mull;

return ((ulong)ah) * bh + (t >> 32) + (tl >> 32);
}
}
}
35 changes: 24 additions & 11 deletions tests/Neo.Extensions.Tests/Factories/UT_RandomNumberFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public void CheckNextSByteInRange()
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);

actualValue = RandomNumberFactory.NextSByte(expectedMax);
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);
Assert.IsTrue(actualValue >= 0 && actualValue <= expectedMax);
}

[TestMethod]
Expand Down Expand Up @@ -76,7 +76,7 @@ public void CheckNextByteInRange()
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);

actualValue = RandomNumberFactory.NextByte(expectedMax);
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);
Assert.IsTrue(actualValue >= 0 && actualValue <= expectedMax);
}

[TestMethod]
Expand All @@ -92,7 +92,7 @@ public void CheckNextInt16InRange()
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);

actualValue = RandomNumberFactory.NextInt16(expectedMax);
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);
Assert.IsTrue(actualValue >= 0 && actualValue <= expectedMax);
}

[TestMethod]
Expand All @@ -105,7 +105,7 @@ public void CheckNextInt16InNegative()
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);

actualValue = RandomNumberFactory.NextInt16(expectedMax);
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);
Assert.IsTrue(actualValue >= 0 && actualValue <= expectedMax);
}

[TestMethod]
Expand All @@ -128,7 +128,7 @@ public void CheckNextUInt16InRange()
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);

actualValue = RandomNumberFactory.NextUInt16(expectedMax);
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);
Assert.IsTrue(actualValue >= 0 && actualValue <= expectedMax);
}

[TestMethod]
Expand All @@ -144,7 +144,7 @@ public void CheckNextInt32InRange()
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);

actualValue = RandomNumberFactory.NextInt32(expectedMax);
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);
Assert.IsTrue(actualValue >= 0 && actualValue <= expectedMax);
}

[TestMethod]
Expand Down Expand Up @@ -177,7 +177,7 @@ public void CheckNextUInt32InRange()
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);

actualValue = RandomNumberFactory.NextUInt32(expectedMax);
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);
Assert.IsTrue(actualValue >= 0 && actualValue <= expectedMax);
}

[TestMethod]
Expand All @@ -193,7 +193,7 @@ public void CheckNextInt64InRange()
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);

actualValue = RandomNumberFactory.NextInt64(expectedMax);
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);
Assert.IsTrue(actualValue >= 0 && actualValue <= expectedMax);
}

[TestMethod]
Expand Down Expand Up @@ -226,7 +226,7 @@ public void CheckNextUInt64InRange()
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);

actualValue = RandomNumberFactory.NextUInt64(expectedMax);
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);
Assert.IsTrue(actualValue >= 0 && actualValue <= expectedMax);
}

[TestMethod]
Expand All @@ -245,7 +245,7 @@ public void CheckNextBigIntegerSizeInBits()
public void CheckNextBigIntegerInRange()
{
var expectedMax = BigInteger.Pow(2, 100);
var expectedMin = BigInteger.Zero;
var expectedMin = BigInteger.Pow(2, 50);

Assert.AreEqual(expectedMax, RandomNumberFactory.NextBigInteger(expectedMax, expectedMax));
Assert.AreEqual(expectedMin, RandomNumberFactory.NextBigInteger(expectedMin, expectedMin));
Expand All @@ -254,7 +254,7 @@ public void CheckNextBigIntegerInRange()
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);

actualValue = RandomNumberFactory.NextBigInteger(expectedMax);
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);
Assert.IsTrue(actualValue >= 0 && actualValue <= expectedMax);
}

[TestMethod]
Expand Down Expand Up @@ -285,7 +285,20 @@ public void CheckNextBigIntegerSmallValues()
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);

actualValue = RandomNumberFactory.NextBigInteger(expectedMax);
Assert.IsTrue(actualValue >= 0 && actualValue <= expectedMax);
}

[TestMethod]
public void CheckNextBigIntegerZero()
{
var expectedMax = BigInteger.Zero;
var expectedMin = BigInteger.Zero;

var actualValue = RandomNumberFactory.NextBigInteger(expectedMin, expectedMax);
Assert.IsTrue(actualValue >= expectedMin && actualValue <= expectedMax);

actualValue = RandomNumberFactory.NextBigInteger(expectedMax);
Assert.IsTrue(actualValue >= 0 && actualValue <= expectedMax);
}
}
}
Loading