.NET Forum / Visual Studio.NET / General / May 2005
Random numbers
|
|
Thread rating:  |
Terry Holland - 25 May 2005 09:55 GMT I am writing an application that needs a list of unique random numbers between Lower and Upper limits.
The code im using is shown along with some result sets. What can I do to make the results more random?
===============================================
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click GetList(50) End Sub Function GetList(ByVal intListLength As Integer) Dim intNumber As Integer For intNumber = 1 To intListLength Debug.WriteLine(RandomNumber(50, 1)) Next End Function
Public Function RandomNumber(ByVal MaxNumber As Integer, Optional ByVal MinNumber As Integer = 0) As Integer Dim objRandmon As New System.Random Return objRandmon.Next(MinNumber, MaxNumber) End Function ===============================================
Here are a few result sets
49, 6, 6, 6, 6, 6, 6, 6, 6, 23, 23, 23, 23, 23, 23, 23, 23, 23, 15, 15, 15, 15, 15, 15, 15, 15, 15, 33, 33, 33, 33, 33, 33, 33, 33, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 42, 42, 42, 42, 42
37, 17, 17, 17, 17, 17, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 3, 3, 3, 3, 3, 3, 3, 3, 3, 44, 44, 44, 44, 44, 44, 44, 44, 44, 13, 13, 13, 13, 13, 13, 13, 5, 5, 5, 5, 5, 5, 22, 22, 22
6, 6, 6, 6, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
38, 38, 38, 38, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 34, 34
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 40, 40, 40, 40, 40, 40
9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 28, 28
Gus Gustafson - 25 May 2005 12:19 GMT Terry, it appears that you do not have a well behaved random number generator. I have attached a C# class that generates well behaved random numbers. However, if you want a quick and dirty use the following:
BEGIN QUICK AND DIRTY
ulong ia = 106 ; ulong ic = 1283 ; ulong im = 6075 ; ulong j = 0 ; ulong jhi = <set to Upper limit> ; ulong jlo = <set to Lower limit> ; ulong jran = ( im - 7 ) ;
jran = ( jran * ia + ic ) % im ; j = jlo + ( ( jhi - jlo + 1 ) * jran ) /im ;
END QUICK AND DIRTY
See section 7.1 and following in
http://www.library.cornell.edu/nr/bookcpdf.html
for a discussion of both, but especially for the quick and dirty. The section includes other constants thgat can be used depending upon the machine overflow.
BEGIN C# class
namespace CNA_Library { using System ; using System.Configuration ; using System.Data ; using System.Data.SqlClient ; using System.Drawing ; using System.Text ; using System.Web ; using System.Web.Mail ; using CNA_Library ;
public class Random_Variants {
// *********************************** Compilation unit constants
const int IA = ( 16807 ) ; const int IM = ( 2147483647 ) ; const float AM = ( 1.0f / ( float ) IM ) ; const int IQ = ( 127773 ) ; const int IR = ( 2836 ) ; const int NTAB = ( 32 ) ; const int NDIV = ( 1 + ( IM - 1 ) / NTAB ) ; const float EPS = ( ( float ) 1.2e-7 ) ; const float RNMX = ( 1.0f - EPS ) ; protected static long[] iv = new long [ NTAB ] ; protected static long iy = 0 ;
// ********************************************************* ran1
/// <remarks> /// "Minimal" random number generator of Park and Miller /// with Bays and Durham shuffle and added safeguards. /// Returns a random variate between 0.0 and 1.0, ex- /// clusive of the endpoint values. /// /// Call with initialize set to a negative integer to /// initialize; thereafter, do not alter initialize /// between successive deviates in a sequence. /// /// RNMX should approximate the largest floating point /// value that is less than 1. /// /// From "Numerical Recipes in C: The Art of Scientific /// Computing", ISBN 0-521-43108-5, pg 280. See section /// 7.1 in /// /// http://www.library.cornell.edu/nr/bookcpdf.html /// </remarks>
private float ran1 ( ref long initialize ) { long j ; long k = 0 ; float temp ; if ( ( initialize <= 0 ) || ( iy == 0 ) ) { // avoid initialize == 0 if ( -( initialize ) < 1 ) { initialize = 1 ; } else { initialize = - ( initialize ) ; } // load shuffle table // ( after 8 warmups) for ( j = ( NTAB + 7 ); ( j >= 0 ); j-- ) { k = ( initialize ) / IQ ; initialize = IA * ( initialize - k * IQ ) - IR * k ; if ( initialize < 0 ) { initialize += IM ; } if ( j < NTAB ) { iv [ j ] = initialize ; } } iy = iv [ 0 ] ; } // starts here when not // initializing
// compute initialize= // (IA*initialize)%IM // without overflow // using Schrange's // method k = ( initialize ) / IQ ; initialize = IA * ( initialize - k * IQ ) - IR * k ; if ( initialize < 0 ) { initialize += IM ; } j = iy / NDIV ; // in range 0..NTAB-1 iy = iv [ j ] ; // retrieve previous iv [ j ] = initialize ; // refill shuffle table
// do not include end- // points in the returned // value if ( ( temp = ( float ) ( AM * iy ) ) > RNMX ) { temp = ( float ) RNMX ; } return ( temp ) ; }
// ***************************************** long_uniform_variate
/// <summary> /// long long_uniform_variate ( long initialize, /// long minimum, /// long maximum ) /// </summary /// <param name='initialize'> /// long containing and initializing indicator, should /// be -1 and then never changed. /// </param> /// <param name='minimum'> /// long containing the smallest long value to be /// returned. /// </param> /// <param name='maximum'> /// long containing the largest long value to be /// returned. /// </param> /// <returns> /// long containing a random value in the range minimum // to maximum, exclusive. This function does not return /// the maximum value. If the value of maximum is de- /// sired, add one to the supplied value. For example, /// if the desired range of values is 1 through 4, includ- /// ing the value 4, invoke the function as: /// /// long_uniform_variate ( 1, 5 ) /// </returns>
public long long_uniform_variate ( ref long initialize, long minimum, long maximum ) {
return ( ( minimum + ( int ) ( ( float ) ( maximum - minimum ) * ran1 ( ref initialize ) ) ) ) ; } } // class } // namespace
END C# class
HTH
Gus
 Signature Gus Gustafson
> I am writing an application that needs a list of unique random numbers > between Lower and Upper limits. [quoted text clipped - 47 lines] > 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 11, 11, 11, 11, 11, 11, 11, 11, 11, > 11, 11, 11, 11, 11, 11, 28, 28 Terry Holland - 25 May 2005 14:23 GMT Thanks for your response Gus
Im not familiar with C# so I'm trying to convert quick and dirty function to VB.Net. I'm ok with most of it but Im not sure what the following line converts to jran = ( jran * ia + ic ) % im ;
With regard to the .NET inbuilt System.Random class, am I to assume that if I need to call this from within a loop to generate a list of 'random' numbers that it is in fact totally useless or am I doing something wrong?
Most examples that I see this code objRandmon.Next(MinNumber, MaxNumber) being used in is to generate one number in response to a user input. As far as I can work out the randomness is in "when the user inputs" rather than anything in this class. While I can see this as being useful in some circumstances it is not very useful for generating lists.
Regards
Terry Holland
> Terry, it appears that you do not have a well behaved random number > generator. I have attached a C# class that generates well behaved random [quoted text clipped - 243 lines] > > 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 11, 11, 11, 11, 11, 11, 11, 11, 11, > > 11, 11, 11, 11, 11, 11, 28, 28 Phil Wilson - 25 May 2005 20:34 GMT You're making a new Random object on every call to RandomNumber. When you don't pass a seed in the constructor, the code uses a time ticker as the seed, so you'll see the same results every time you call until the tick count increases, then you get the same value while that tick count is the current one.
For a proper sequence, and better performance, create the Random object once, perhaps with a seed of your choice, then call Next on that.
 Signature Phil Wilson [MVP Windows Installer] ----
> Thanks for your response Gus > [quoted text clipped - 287 lines] > 11, >> > 11, 11, 11, 11, 11, 11, 28, 28 Terry Holland - 31 May 2005 09:42 GMT Thanks
Works fine now
Terry
M. Foco - 26 May 2005 14:36 GMT > Public Function RandomNumber(ByVal MaxNumber As Integer, Optional ByVal > MinNumber As Integer = 0) As Integer > Dim objRandmon As New System.Random > Return objRandmon.Next(MinNumber, MaxNumber) > End Function Try creating just one global System.Random object. You'll gain both speed and correctness. The System.Random number generator is initialized with the timer, creating two different random number generators in short time will initialize them both with the same sequence (and you'll get repeating numbers).
-- Marco *PaN!* Foco
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|