public static BigInt Random(this Random generator, BigInt limit) {
ContractUtils.Requires(limit.Sign > 0, "limit");
ContractUtils.RequiresNotNull(generator, "generator");
BigInt res = BigInt.Zero;
while (true) {
// if we've run out of significant digits, we can return the total
if (limit == BigInt.Zero) {
return res;
}
// if we're small enough to fit in an int, do so
int iLimit;
if (limit.AsInt32(out iLimit)) {
return res + generator.Next(iLimit);
}
// get the 3 or 4 uppermost bytes that fit into an int
int hiData;
byte[] data = limit.ToByteArray();
int index = data.Length;
while (data[--index] == 0) ;
if (data[index] < 0x80) {
hiData = data[index] << 24;
data[index--] = (byte)0;
} else {
hiData = 0;
}
hiData |= data[index] << 16;
data[index--] = (byte)0;
hiData |= data[index] << 8;
data[index--] = (byte)0;
hiData |= data[index];
data[index--] = (byte)0;
// get a uniform random number for the uppermost portion of the bigint
byte[] randomData = new byte[index + 2];
generator.NextBytes(randomData);
randomData[index + 1] = (byte)0;
res += new BigInt(randomData);
res += (BigInt)generator.Next(hiData) << ((index + 1) * 8);
// sum it with a uniform random number for the remainder of the bigint
limit = new BigInt(data);
}
}