Cannot randomize from a class

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Hi, I'm using the Random class to return 5 random numbers which then are
added to a string.

When I do it in a controls event, such as button_ click, the numbers are
random as expected, but when I call the random function as a method of a
class, all the numbers are the same for each call to the class.
For example:
(Button click calls the myRandomObject.ReturnValue method)

button click produces 5,5,5
next button click produces 7,7,7
third button click produces 2,2,2

This is basically what is being called when the myRandomObject.ReturnValue
method is called:

Random r = new Random();
string op = r.Next(48,58).ToString();

Why does this work in a button click event but not from a class method? I
would think that the Random instance would be destroyed with each call to the
method.

Any ideas?

Thanks for your help on this
Ant.
 
Ant said:
Hi, I'm using the Random class to return 5 random numbers which then are
added to a string.

And I suspect you're creating a new instance of Random for each random
number. That uses a seed based on the current time - and if you create
many instances within a sufficiently short space of time, you'll get
the same seed for each instance, and therefore the same random numbers.

You should be repeatedly using a single instance of Random
See http://msmvps.com/blogs/jon.skeet/archive/2005/12/02/77520.aspx for
an easy solution - basically you can use the StaticRandom class in my
Miscellaneous Utility library at
http://www.pobox.com/~skeet/csharp/miscutil to make your life easier.

Jon
 
Hi, I'm using the Random class to return 5 random numbers which then are
added to a string.

When I do it in a controls event, such as button_ click, the numbers are
random as expected, but when I call the random function as a method of a
class, all the numbers are the same for each call to the class.
For example:
(Button click calls the myRandomObject.ReturnValue method)

button click produces 5,5,5
next button click produces 7,7,7
third button click produces 2,2,2

This is basically what is being called when the myRandomObject.ReturnValue
method is called:

Random r = new Random();
string op = r.Next(48,58).ToString();

Why does this work in a button click event but not from a class method? I
would think that the Random instance would be destroyed with each call to the
method.

Any ideas?

Thanks for your help on this
Ant.

When you use the constructor without arguments, the seed is used from
the system clock. This means that if you use this repeatedly (in a
loop), the various instances start with the SAME seed value, so
generate the SAME sequence.

So you need to use just a single Random instance to generate a list of
random numbers. One way would be to use a static instance:
(untested code)

class MyRandomObject
{
private static Random rnd = new Random();

public static string NextChar()
{
string op = rnd.Next(48,58).ToString();
return op;
}
}

Hans Kesting
 
Hi Ant,

you have to take into account that creating two Random objects with
identical seeds will generate the same series of numbers. In your case, you
didn't specify a seed for the Random class constructor, so the System uses
Environment.TickCount (ms elapsed since system start) as default seed. If you
construct x new Random objects in the same millisecond using the default
constructor, your x random objects will have the same seed, and thus generate
the same serie of "random" values.

In your case, you didn't click the button fast enough to see this behavior :-)

Consider the following to demo apps, the first one will have a lot of
similar values in the console output, the second one will have more random
results:

public class MyTestApp
{
public static void Main()
{
for (System.Int32 i=0;i<100;i++)
{
System.Console.WriteLine(new System.Random().Next(45,58));
}
}
}

public class MyTestApp
{
public static void Main()
{
System.Random r = new System.Random();
for (System.Int32 i=0;i<1000;i++)
{
System.Console.WriteLine(r.Next(45,58));
}
}
}

to summarize: either construct one random object and reuse, or make sure you
have a different seed when creating the next random object. (I favor the
first solution)

HTH,
Baileys
 
I don't know about your exact scenario (not enough code to reproduce), but a
better option is to cache the Random() instance between calls (presumably in
a field if you are using a wrapper class). This means that subsequent calls
will return pseudo-random results (updating the object seed each call to
Next()), where-as "new Random()" simply initialises a new object using the
time to create a seed.

Personally, unless I need reproducable results (with same starting seed), I
tend to use a static wrapper, so that all my code can use
MyWrapper.Next(48,58) to share the same random object (obviously you may
need to make this thread-safe).

Marc
 
Actually the docs for Environment.TickCount specify that its resolution
cannot be < 500ms, not 1ms as i mentioned...
 
Hans said:
When you use the constructor without arguments, the seed is used from
the system clock. This means that if you use this repeatedly (in a
loop), the various instances start with the SAME seed value, so
generate the SAME sequence.

So you need to use just a single Random instance to generate a list of
random numbers. One way would be to use a static instance:
(untested code)

class MyRandomObject
{
private static Random rnd = new Random();

public static string NextChar()
{
string op = rnd.Next(48,58).ToString();
return op;
}
}

Note, however, than Random is not thread-safe. It sounds like it may
not be a problem in the OP's case, but you need to make sure you don't
use the same instance across multiple threads.

Jon
 
Thank you all, you were all right on target. I was using a new instance of
the Random class with each call. Hence the seed was the same. I just worked
around it by creating the string within the method being called using a
single instance of the Random class.

Thanks all.
 
Back
Top