Results 1 to 3 of 3

Thread: A More Random Random Class

  1. #1

    Thread Starter
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    A More Random Random Class

    C# version here.

    The .NET Framework includes the System.Random class, whose job it is to generate random numbers. It does so using a sequence based on a seed value, which is based on the system time by default. There are numerous possible seeds and predicting the exact time that a Random object will be created is not easy. That, coupled with the fact that the distribution of numbers generated by the sequence satisfies various statistical requirements for randomness, means that the Random class is quite suitable for most of your random number needs.

    The main issue with the Random class is that, given a particular seed, the sequence will always produce the same numbers. That can actually be good for some testing scenarios but it does mean that the results could be manipulated. Where very high levels of unpredictability are required, the Random class is not suitable.

    I've seen a number of people use various methods to generate more random random numbers. That's not really necessary though. The .NET Framework also includes the System.Security.Cryptography.RNGCryptoServiceProvider class for generating random numbers. It's output is sufficiently random for use in cryptography, so there's really no need for anything more random than that.

    One issue with the RNGCryptoServiceProvider class, though, is that it populates Byte arrays with random values. That's not always completely convenient though, as the most common need in applications is a random Integer within a specific range. The Random class is nice and easy to use in that scenario, thanks to its Next method. What if we could combine the ease of use of the Random class with the increased randomness of the RNGCryptoServiceProvider class?

    As it happens, we can. The Random class has a Protected method named Sample that generates a Double in the range 0.0 <= x < 1.0. The result of that method is then used in the other methods to generate Integers in a range. We can define our own class that inherits Random and overrides that Sample method to use RNGCryptoServiceProvider internally. Here's one I prepared earlier:
    vb.net Code:
    1. Imports System.Security.Cryptography
    2.  
    3. ''' <summary>
    4. ''' Represents a random number generator, a device that produces a sequence of numbers that meet cryptographic requirements for randomness.
    5. ''' </summary>
    6. ''' <remarks>
    7. ''' Seed values are meaningless because this class uses a cryptographic service provider internally rather than a pseudo-random sequence.
    8. ''' </remarks>
    9. Public Class CryptoRandom
    10.     Inherits Random
    11.     Implements IDisposable
    12.  
    13.     ''' <summary>
    14.     ''' The internal random number generator.
    15.     ''' </summary>
    16.     Private ReadOnly rng As New RNGCryptoServiceProvider
    17.  
    18.     ''' <summary>
    19.     ''' Returns a random number between 0.0 and 1.0.
    20.     ''' </summary>
    21.     ''' <returns>
    22.     ''' A double-precision floating point number greater than or equal to 0.0, and less than 1.0.
    23.     ''' </returns>
    24.     ''' <remarks>
    25.     ''' Uses a cryptographic service provider internally rather than a pseudo-random sequence.
    26.     ''' </remarks>
    27.     Protected Overrides Function Sample() As Double
    28.         Dim data(7) As Byte
    29.         Dim number As ULong
    30.  
    31.         Do
    32.             'Get 8 random bytes.
    33.             rng.GetBytes(data)
    34.  
    35.             'Convert the bytes to an unsigned 64-bit number.
    36.             number = BitConverter.ToUInt64(data, 0)
    37.         Loop While number = ULong.MaxValue 'The result must be less than 1.0
    38.  
    39.         'Divide the number by the largest possible unsigned 64-bit number to get a value in the range 0.0 <= N < 1.0.
    40.         Return number / ULong.MaxValue
    41.     End Function
    42.  
    43. #Region "IDisposable Support"
    44.  
    45.     Private disposedValue As Boolean ' To detect redundant calls
    46.  
    47.     ' IDisposable
    48.     Protected Overridable Sub Dispose(disposing As Boolean)
    49.         If Not Me.disposedValue Then
    50.             If disposing Then
    51.                 'Dispose the underlying cryptographic random number generator.
    52.                 rng.Dispose()
    53.             End If
    54.         End If
    55.  
    56.         Me.disposedValue = True
    57.     End Sub
    58.  
    59.     ' This code added by Visual Basic to correctly implement the disposable pattern.
    60.     Public Sub Dispose() Implements IDisposable.Dispose
    61.         ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
    62.         Dispose(True)
    63.         GC.SuppressFinalize(Me)
    64.     End Sub
    65.  
    66. #End Region
    67.  
    68. End Class
    You can create an instance of that class and use it in pretty much exactly the same way as you would a Random object. The only difference is that you will need to call its Dispose method when you're done, in order to dispose the internal RNGCryptoServiceProvider object. Sample usage:
    vb.net Code:
    1. Public Class Form1
    2.  
    3.     Private ReadOnly rng As New CryptoRandom
    4.  
    5.     Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    6.         'Generate 10 random numbers.
    7.         Dim numbers(9) As Integer
    8.  
    9.         For i = 0 To numbers.GetUpperBound(0)
    10.             'Generate numbers in the range 0 <= n <= 1000
    11.             numbers(i) = rng.Next(1001)
    12.         Next
    13.  
    14.         MessageBox.Show(String.Join(Environment.NewLine, numbers),
    15.                         "10 Random Numbers")
    16.     End Sub
    17.  
    18.     Private Sub Form1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
    19.         rng.Dispose()
    20.     End Sub
    21.  
    22. End Class
    Attached Files Attached Files
    Last edited by jmcilhinney; May 22nd, 2013 at 03:48 AM.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  2. #2
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: A More Random Random Class

    A couple notes on this class:

    1) The RNGCryptoServiceProvider didn't have a Dispose method until Framework 4.0, so if you use this class while compiling against framework 3.5, you will need to comment out the rng.Dispose line in the Dispose method.

    2) A comparison test of the relative speed of this random test versus the basic Random object shows what should be expected: The standard Random class is about 100x faster than the cryptographic random test. Both are VERY fast, though, so speed really isn't an issue. The speed might become an issue if you are going to be generating LOTS of random values in a time-critical loop, but for all other purposes, either method will be suitably fast.
    My usual boring signature: Nothing

  3. #3

    Thread Starter
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: A More Random Random Class

    Quote Originally Posted by Shaggy Hiker View Post
    The RNGCryptoServiceProvider didn't have a Dispose method until Framework 4.0, so if you use this class while compiling against framework 3.5, you will need to comment out the rng.Dispose line in the Dispose method.
    I didn't realise that. Thanks for pointing it out.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width