Search code examples
c#randombiginteger

Why is C# BigInteger not always the same bit length?


I am trying to generate 1024bits random numbers with this code:

var bytes = RandomNumberGenerator.GetBytes(128);
var number = new BigInteger(bytes);

But when I inspect my number using BigInteger methods, its BitLength is always different.

For example, when running this code:

for (int i = 0; i < 5; i++)
{
    var bi = new BigInteger(RandomNumberGenerator.GetBytes(128));
    Console.WriteLine($"{i}: {bi.GetBitLength()} bits | {bi.GetByteCount()} bytes");
}

I am getting this output:

0: 1021 bits | 128 bytes
1: 1023 bits | 128 bytes
2: 1022 bits | 128 bytes
3: 1021 bits | 128 bytes
4: 1022 bits | 128 bytes

What am I doing wrong / not understanding here ?


Solution

  • GetBitLength is documented as:

    Gets the number of bits required for shortest two's complement representation of the current instance without the sign bit.

    And also, helpfully:

    For positive integers the return value is equal to the ordinary binary representation string length.

    Now, consider two (very small) BigInteger values - 1 and 3. It only takes 1 bit to represent the integer value 1, whereas it takes 2 bits to represent the integer 3.

    Effectively, any leading 0 bits which might have been passed in the original byte array aren't included in GetBitLength().

    I suspect that's absolutely fine for you, but it will definitely depend on what you're planning to do with the result. To put it another way: if you only wanted 4 bit numbers, would you want values between 0 and 15 inclusive, or between 8 and 15 inclusive? Because requiring GetBitLength() to return 4 would make you generate the latter... (That's effectively "3 random bits and a leading bit that's always 1".)