Quote Originally Posted by boops boops View Post
Thank you for your kind words. But Boops boops <> Betty Boop. For my true profile, see here.

My thinking for the method was as follows. Setting a number of bits at random produces a random number; the randomness is as good as the random number generator used to set the bits, or a function of it at least. Random.NextBytes provides a method of setting the bits at random in convenient batches of 8, but doesn't introduce any non-randomness apart from the total number of bits.

I wondered whether knocking out the high order bits might affect the randomness, and I reasoned as follows. Suppose you want a random number in the range 1 to 4, and you have a normal 6-faced die (singular of dice). When you throw the die, each number has a one sixth chance of occurring. What happens if you just ignore throws of 5 or 6 to get the required random throw? The chances of 1, 2, 3 and 4 are still equal (one sixth). So excluding certain numbers from a set of random values does not necessarily change the randomness of those that remain. Zeroizing the high end bits does nothing except reduce the range of values.

BB
I seperated your function into 2 functions (like in Matt's example) to get rid of the looping (which was the running debate at the time), and this seems to perform a tad faster on the few examples I tried:
vb.net Code:
  1. Private Function RandomBigInteger_Max(maximum As BigInteger) As BigInteger
  2.         If maximum <= 0 Then Throw New Exception("Maximum must be positive!")
  3.  
  4.         Dim maxBytes() As Byte = maximum.ToByteArray
  5.         Dim count As Integer = maxBytes.Count
  6.         Dim resultBytes(count - 1) As Byte
  7.  
  8.         'Get a random byte array of the same length as the maxBytes:
  9.         _random.NextBytes(resultBytes)
  10.  
  11.         'zeroise bits in the most significant byte which are leading zeros in maxBytes:
  12.         For i As Integer = 7 To 0 Step -1
  13.             Dim bitmask = 1 << i
  14.             If (maxBytes.Last And bitmask) = bitmask Then
  15.                 'If the tested bit is 1, there are no more leading zeros:
  16.                 Exit For
  17.             Else
  18.                 'Zeroize the tested byte:
  19.                 resultBytes(count - 1) = CByte(resultBytes.Last And (Not bitmask))
  20.             End If
  21.         Next
  22.  
  23.         Return New BigInteger(resultBytes)
  24.     End Function
  25.     Private Function RandomBigInteger_Gen(minimum As BigInteger, maximum As BigInteger) As BigInteger
  26.  
  27.         Dim biDiff As BigInteger = maximum - minimum
  28.         If biDiff < 0 Then Throw New Exception("Maximum must be more than minimum!")
  29.  
  30.         Return BigInteger.Add(RandomBigInteger_Max(biDiff), minimum)
  31.  
  32.     End Function
To test, I used:
Code:
        bimin = New BigInteger(75426795804)
        bimax = New BigInteger(479207684327642)

        Dim s As New Stopwatch

        s.Start()
        For i = 1 To 10000000
            RandomBigInteger(bimin, bimax)
        Next
        s.Stop()

        TextBox1.AppendText(String.Format("Time for BB algo: {0}{1}", s.ElapsedMilliseconds, Environment.NewLine))

        s.Reset()
        s.Start()
        For i = 1 To 10000000
            RandomBigInteger_Gen(bimin, bimax)
        Next
        s.Stop()

        TextBox1.AppendText(String.Format("Time for Gen algo: {0}{1}", s.ElapsedMilliseconds, Environment.NewLine))
Unless I screwed something up (again), you have succeded in making a non-looping truly random bigint generator