Skip to content

Commit bef5ee0

Browse files
Wi1l-B0tshargon
authored andcommitted
Optimize: impl GetLowestSetBit by TrailingZeroCount if available (neo-project#4030)
* Optimize: impl GetLowestSetBit by TrailingZeroCount if available * Update src/Neo.Extensions/BigIntegerExtensions.cs --------- Co-authored-by: Shargon <[email protected]>
1 parent 9ec0032 commit bef5ee0

File tree

1 file changed

+23
-15
lines changed

1 file changed

+23
-15
lines changed

src/Neo.Extensions/BigIntegerExtensions.cs

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,33 @@ namespace Neo.Extensions
1818
{
1919
public static class BigIntegerExtensions
2020
{
21+
internal static int TrailingZeroCount(byte[] b)
22+
{
23+
var w = 0;
24+
while (b[w] == 0) w++;
25+
for (var x = 0; x < 8; x++)
26+
{
27+
if ((b[w] & 1 << x) > 0)
28+
return x + w * 8; // cannot greater than 2Gib
29+
}
30+
return -1; // unreachable, because returned earlier if value is zero
31+
}
32+
2133
/// <summary>
22-
/// Finds the lowest set bit in the specified value.
34+
/// Finds the lowest set bit in the specified value. If value is zero, returns -1.
2335
/// </summary>
24-
/// <param name="value">The value to find the lowest set bit in.</param>
36+
/// <param name="value">The value to find the lowest set bit in. The value.GetBitLength cannot greater than 2Gib.</param>
2537
/// <returns>The lowest set bit in the specified value.</returns>
26-
/// <exception cref="Exception">Thrown when the value is zero.</exception>
38+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2739
public static int GetLowestSetBit(this BigInteger value)
2840
{
29-
if (value.Sign == 0)
30-
return -1;
31-
var b = value.ToByteArray();
32-
var w = 0;
33-
while (b[w] == 0)
34-
w++;
35-
for (var x = 0; x < 8; x++)
36-
if ((b[w] & 1 << x) > 0)
37-
return x + w * 8;
38-
throw new Exception("The value is zero.");
41+
if (value.Sign == 0) return -1; // special case for zero. TrailingZeroCount returns 32 in standard library.
42+
43+
#if NET7_0_OR_GREATER
44+
return (int)BigInteger.TrailingZeroCount(value);
45+
#else
46+
return TrailingZeroCount(value.ToByteArray());
47+
#endif
3948
}
4049

4150
/// <summary>
@@ -97,7 +106,6 @@ public static BigInteger ModInverse(this BigInteger value, BigInteger modulus)
97106
/// <param name="value">The value to test.</param>
98107
/// <param name="index">The index of the bit to test.</param>
99108
/// <returns>True if the specified bit is set in the specified value, otherwise false.</returns>
100-
101109
[MethodImpl(MethodImplOptions.AggressiveInlining)]
102110
public static bool TestBit(this BigInteger value, int index)
103111
{
@@ -117,7 +125,7 @@ public static BigInteger Sum(this IEnumerable<BigInteger> source)
117125
}
118126

119127
/// <summary>
120-
/// Converts a <see cref="BigInteger"/> to byte array and eliminates all the leading zeros.
128+
/// Converts a <see cref="BigInteger"/> to byte array in little-endian and eliminates all the leading zeros.
121129
/// If the value is zero, it returns an empty byte array.
122130
/// </summary>
123131
/// <param name="value">The <see cref="BigInteger"/> to convert.</param>

0 commit comments

Comments
 (0)