Skip to content

Commit 403aa58

Browse files
tannergoodingdakersnartkekalainen
authored
Fix bug with BigInteger.TrailingZeroCount (#77727) (#78174)
* Fix bug with BigInteger.TrailingZeroCount * Update src/libraries/System.Runtime.Numerics/tests/BigIntegerTests.GenericMath.cs Co-authored-by: Tommi Kekäläinen <76913562+tkekalainen@users.noreply.github.com> * Update negative code path * Simplify logic for handling negative values * Update src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs Co-authored-by: Tommi Kekäläinen <76913562+tkekalainen@users.noreply.github.com> * Update comment Co-authored-by: Tommi Kekäläinen <76913562+tkekalainen@users.noreply.github.com> Co-authored-by: Drew Kersnar <18474647+dakersnar@users.noreply.github.com> Co-authored-by: Tommi Kekäläinen <76913562+tkekalainen@users.noreply.github.com>
1 parent abecfbe commit 403aa58

File tree

2 files changed

+11
-31
lines changed

2 files changed

+11
-31
lines changed

src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3481,42 +3481,19 @@ public static BigInteger TrailingZeroCount(BigInteger value)
34813481

34823482
ulong result = 0;
34833483

3484-
if (value._sign >= 0)
3485-
{
3486-
// When the value is positive, we simply need to do a tzcnt for all bits until we find one set
3487-
3488-
uint part = value._bits[0];
3484+
// Both positive values and their two's-complement negative representation will share the same TrailingZeroCount,
3485+
// so the sign of value does not matter and both cases can be handled in the same way
34893486

3490-
for (int i = 1; (part == 0) && (i < value._bits.Length); i++)
3491-
{
3492-
part = value._bits[i];
3493-
result += (sizeof(uint) * 8);
3487+
uint part = value._bits[0];
34943488

3495-
i++;
3496-
}
3497-
3498-
result += uint.TrailingZeroCount(part);
3499-
}
3500-
else
3489+
for (int i = 1; (part == 0) && (i < value._bits.Length); i++)
35013490
{
3502-
// When the value is negative, we need to tzcnt the two's complement representation
3503-
// We'll do this "inline" to avoid needing to unnecessarily allocate.
3504-
3505-
uint part = ~value._bits[0] + 1;
3506-
3507-
for (int i = 1; (part == 0) && (i < value._bits.Length); i++)
3508-
{
3509-
// Simply process bits, adding the carry while the previous value is zero
3510-
3511-
part = ~value._bits[i] + 1;
3512-
result += (sizeof(uint) * 8);
3513-
3514-
i++;
3515-
}
3516-
3517-
result += uint.TrailingZeroCount(part);
3491+
part = value._bits[i];
3492+
result += (sizeof(uint) * 8);
35183493
}
35193494

3495+
result += uint.TrailingZeroCount(part);
3496+
35203497
return result;
35213498
}
35223499

src/libraries/System.Runtime.Numerics/tests/BigIntegerTests.GenericMath.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,9 @@ public static void TrailingZeroCountTest()
366366

367367
Assert.Equal((BigInteger)63, BinaryIntegerHelper<BigInteger>.TrailingZeroCount(Int64MaxValuePlusOne));
368368
Assert.Equal((BigInteger)0, BinaryIntegerHelper<BigInteger>.TrailingZeroCount(UInt64MaxValue));
369+
370+
Assert.Equal((BigInteger)1000, BinaryIntegerHelper<BigInteger>.TrailingZeroCount(BigInteger.Pow(2, 1000)));
371+
Assert.Equal((BigInteger)1000, BinaryIntegerHelper<BigInteger>.TrailingZeroCount(-BigInteger.Pow(2, 1000)));
369372
}
370373

371374
[Fact]

0 commit comments

Comments
 (0)