-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Description
Description
I found a problem with the BigInteger unsigned right shift operation (>>>
) when the BigInteger is negative.
BigInteger represents an infinite-precision signed binary integer in two's complement form, but it does not have a predefined bit length. Therefore, it should not be treated as a fixed-length integer and subjected to unsigned right shift with some arbitrary or randomly chosen bit length.
Unsigned right shift can be seen as performing a signed right shift (>>
) after masking the bits with ((1 << N) - 1). The current implementation incorrectly uses the total number of bits in the minimum number of UInt32 units needed to store the BigInteger as the fixed length N, which is inappropriate because it is unnatural and exposes implementation details. (Note that we may consider upgrading BigInteger to use UInt64 units instead.)
We observe that the larger N is, the more bits are preserved, so for BigInteger, the limiting case is that all bits are preserved, which means that the natural definition of unsigned right shift in infinite precision is the same as signed right shift, because the masking operation does not change any bits. (Although BigInteger has a GetBitLength() value, using it (or its variant) as the fixed length for unsigned right shift is also not very natural.)
Reproduction Steps
.
Expected behavior
The BigInteger unsigned right shift operation should behave exactly the same as the signed right shift operation, regardless of the internal representation of the BigInteger.
Actual behavior
The BigInteger unsigned right shift operation is based on the internal representation of the BigInteger, and produces unexpected results when the BigInteger is negative.
Regression?
No response
Known Workarounds
No response
Configuration
No response
Other information
No response