System.Random

  • Thread starter Thread starter Jon Agiato
  • Start date Start date
J

Jon Agiato

Hello,
I am sure this problem is easy to spot but I have been at this project all
day and the frustration has finally overcome me. I am using this function
in order to produce a standard normal distribution random number generator
and then using the function in another part of my program in order to use
the value. This function is called for many iterations. The problem is,
through each run I am getting the exact same number generated from this
function with the occasional slight variation. How can I make this function
create numbers randomly? I am thinking since it is being run so fast the
same seed is being used, but how can I change that? This is C# code, used
in a web application. Here's the code:

private double sndRNG()
{
const double quantityRN = 16.0;

uint start = 0;
double tmp = 0.0;
Random randomNumber = new Random();
for(; start != quantityRN; ++start)
{
tmp += Convert.ToDouble(randomNumber.Next(10));
}

double tmp2 = tmp / quantityRN;

return (tmp2 - 4.5) * 4.0 / Math.Sqrt(8.25);
}

Thanks for any and all suggestions.
 
Try using a seed value for the Random object constructor.
This should create a pseudo-random result.

Hope this helps.
 
[...]

The Random class takes some time value (afaik the currentticks) as seed.
that may be not enough difference for your application.

one easy to do thing would be to write your own pseudo-random function.

this one should do nicely:

public class Rand
{
private static int seed = 31337; //some value

Public int NextInt()
{
seed= ( seed * 15625 + 1 ) & 32767;
return seed;
}
}
 
Jon said:
Hello,
I am sure this problem is easy to spot but I have been at this project all
day and the frustration has finally overcome me. I am using this function
in order to produce a standard normal distribution random number generator
and then using the function in another part of my program in order to use
the value. This function is called for many iterations. The problem is,
through each run I am getting the exact same number generated from this
function with the occasional slight variation. How can I make this function
create numbers randomly? I am thinking since it is being run so fast the
same seed is being used, but how can I change that? This is C# code, used
in a web application. Here's the code:

private double sndRNG()
{
const double quantityRN = 16.0;

uint start = 0;
double tmp = 0.0;
Random randomNumber = new Random();
for(; start != quantityRN; ++start)
{
tmp += Convert.ToDouble(randomNumber.Next(10));
}

double tmp2 = tmp / quantityRN;

return (tmp2 - 4.5) * 4.0 / Math.Sqrt(8.25);
}

Thanks for any and all suggestions.

You can seed the rng only once by making it a private member of your
class rather than a local in your method:

private Random randomNumber = new Random();

private double sndRNG()
{
const double quantityRN = 16.0;

uint start = 0;
double tmp = 0.0;
// Random randomNumber = new Random();
for(; start != quantityRN; ++start)
{
tmp += Convert.ToDouble(randomNumber.Next(10));
}

double tmp2 = tmp / quantityRN;

return (tmp2 - 4.5) * 4.0 / Math.Sqrt(8.25);
}

Now the generator is seeded only once - when your class is instantiated.
 
Jon said:
Hello,
I am sure this problem is easy to spot but I have been at this project all
day and the frustration has finally overcome me. I am using this function
in order to produce a standard normal distribution random number generator
and then using the function in another part of my program in order to use
the value. This function is called for many iterations. The problem is,
through each run I am getting the exact same number generated from this
function with the occasional slight variation. How can I make this function
create numbers randomly? I am thinking since it is being run so fast the
same seed is being used, but how can I change that? This is C# code, used
in a web application. Here's the code:

private double sndRNG()
{
const double quantityRN = 16.0;

uint start = 0;
double tmp = 0.0;
Random randomNumber = new Random();
for(; start != quantityRN; ++start)
{
tmp += Convert.ToDouble(randomNumber.Next(10));
}

double tmp2 = tmp / quantityRN;

return (tmp2 - 4.5) * 4.0 / Math.Sqrt(8.25);
}

Thanks for any and all suggestions.


Another comment that I forgot to include in my previous posting. I have
seen evidence (but haven't looked very closely at the issue) that the
Random class provides a *very* poor distribution. It's possible that
this has been fixed in the Framework 1.1 - if it's really a problem at all.

If your application really needs a decent distribution of random
numbers, then you might want to look at the RNGCryptoServiceProvider
class to get higher quality.
 
Jon Agiato said:
Hello,
.... I am using this function
in order to produce a standard normal distribution random number generator
and then using the function in another part of my program in order to use
the value. This function is called for many iterations. The problem is,
through each run I am getting the exact same number generated from this
function with the occasional slight variation. How can I make this function
create numbers randomly?

As others have mentioned, you'll want to create your System.Random object
once and reuse it instead of recreating it for each function call.

Adding 10 random values will generate an approximately normal distribution,
but you can do this directly with just two random values, as follows:

using System;

class Normal
{
static Random rand = new Random();

public static double sndRNG()
{
double x = rand.NextDouble();
double y = rand.NextDouble();
return Math.Sqrt(-2.0 * Math.Log(x)) * Math.Cos(Math.Pi * y);
}
}

class App
{
public static int Main()
{
Console.WriteLine(Normal.sndRNG());
}
}
 
Thanks for all the suggestions, I tried all of them but I am still getting
the same numbers each time. When the user presses the button I have it for
testing so that I can see the values the application generated in a label.
With one press, all of the numbers are the same. With successive presses we
get different numbers, but not with the single press. Here is a larger
chunk of code:

static Random randomNumber = new Random();

private double sndRNG()
{
const double QUANTITYRN = 16.0;

uint start = 0;
double tmp = 0.0;

for(; start != QUANTITYRN; ++start)
{
tmp += Convert.ToDouble(randomNumber.Next(10));
}

double tmp2 = tmp / QUANTITYRN;

return (tmp2 - 4.5) * 4.0 / Math.Sqrt(8.25);
}

private void runSimulation_Click(object sender, System.EventArgs e)
{
double sampleSize = new double();
try
{
if(Convert.ToDouble(SampleSize.Text) > 0 &&
Convert.ToDouble(SampleSize.Text) <= 30)
{
sampleSize = Convert.ToDouble(SampleSize.Text);
}
else
{
sizeRangeError.Text = "Valid range: (0, 30]";
}
}
catch(System.FormatException)
{
sizeRangeError.Text = "Valid range: (0, 30]";
}

double draws = new double();
try
{
if(Convert.ToDouble(Draws.Text) > 0 && Convert.ToDouble(Draws.Text) <=
100)
{
draws = Convert.ToDouble(Draws.Text);
}
else
{
drawRangeError.Text = "Valid range: (0, 100]";
}
}
catch(System.FormatException)
{
drawRangeError.Text = "Valid range: (0, 100]";
}

CInterval cInterval = new CInterval();
ArrayList contIntervals = new ArrayList();

uint start = 0;
for(; start != draws; ++start)
{
double temp = 0.0;
uint star = 0;
for(; star != sampleSize; ++star)
{
temp += sndRNG();
}

double avgRN = temp / sampleSize;
cInterval.setLower(avgRN - 1.96 / Math.Sqrt(sampleSize));
cInterval.setUpper(avgRN + 1.96 / Math.Sqrt(sampleSize));

const double ZERO = 0.0;
if(cInterval.getLower() == ZERO || cInterval.getUpper() == ZERO)
{
cInterval.setValid(true);
}
else if(cInterval.getLower() < ZERO && cInterval.getUpper() > ZERO)
{
cInterval.setValid(true);
}
else
{
cInterval.setValid(false);
}

contIntervals.Add(cInterval);
}

// calculate percentages, and update labels
uint good = 0, bad = 0;
foreach(CInterval CI in contIntervals)
{
if(CI.getValid() == true)
{
++good;
}
else if(CI.getValid() == false)
{
++bad;
}

// for testing
Label2.Text += CI.getLower() + ", " + CI.getUpper() + " ";
}

Label5.Text = good.ToString();
Label7.Text = bad.ToString();
}
}

Thanks again for any and all suggestions!
 
Use System.Security namespace for random if you need good randomisation.


Jon Agiato said:
Thanks for all the suggestions, I tried all of them but I am still getting
the same numbers each time. When the user presses the button I have it for
testing so that I can see the values the application generated in a label.
With one press, all of the numbers are the same. With successive presses we
get different numbers, but not with the single press. Here is a larger
chunk of code:

static Random randomNumber = new Random();

private double sndRNG()
{
const double QUANTITYRN = 16.0;

uint start = 0;
double tmp = 0.0;

for(; start != QUANTITYRN; ++start)
{
tmp += Convert.ToDouble(randomNumber.Next(10));
}

double tmp2 = tmp / QUANTITYRN;

return (tmp2 - 4.5) * 4.0 / Math.Sqrt(8.25);
}

private void runSimulation_Click(object sender, System.EventArgs e)
{
double sampleSize = new double();
try
{
if(Convert.ToDouble(SampleSize.Text) > 0 &&
Convert.ToDouble(SampleSize.Text) <= 30)
{
sampleSize = Convert.ToDouble(SampleSize.Text);
}
else
{
sizeRangeError.Text = "Valid range: (0, 30]";
}
}
catch(System.FormatException)
{
sizeRangeError.Text = "Valid range: (0, 30]";
}

double draws = new double();
try
{
if(Convert.ToDouble(Draws.Text) > 0 && Convert.ToDouble(Draws.Text) <=
100)
{
draws = Convert.ToDouble(Draws.Text);
}
else
{
drawRangeError.Text = "Valid range: (0, 100]";
}
}
catch(System.FormatException)
{
drawRangeError.Text = "Valid range: (0, 100]";
}

CInterval cInterval = new CInterval();
ArrayList contIntervals = new ArrayList();

uint start = 0;
for(; start != draws; ++start)
{
double temp = 0.0;
uint star = 0;
for(; star != sampleSize; ++star)
{
temp += sndRNG();
}

double avgRN = temp / sampleSize;
cInterval.setLower(avgRN - 1.96 / Math.Sqrt(sampleSize));
cInterval.setUpper(avgRN + 1.96 / Math.Sqrt(sampleSize));

const double ZERO = 0.0;
if(cInterval.getLower() == ZERO || cInterval.getUpper() == ZERO)
{
cInterval.setValid(true);
}
else if(cInterval.getLower() < ZERO && cInterval.getUpper() > ZERO)
{
cInterval.setValid(true);
}
else
{
cInterval.setValid(false);
}

contIntervals.Add(cInterval);
}

// calculate percentages, and update labels
uint good = 0, bad = 0;
foreach(CInterval CI in contIntervals)
{
if(CI.getValid() == true)
{
++good;
}
else if(CI.getValid() == false)
{
++bad;
}

// for testing
Label2.Text += CI.getLower() + ", " + CI.getUpper() + " ";
}

Label5.Text = good.ToString();
Label7.Text = bad.ToString();
}
}

Thanks again for any and all suggestions!

--
Jon Agiato
(e-mail address removed)
AOL IM: agiatojon
http://www.agiato.net
Bret Mulvey said:
As others have mentioned, you'll want to create your System.Random object
once and reuse it instead of recreating it for each function call.

Adding 10 random values will generate an approximately normal distribution,
but you can do this directly with just two random values, as follows:

using System;

class Normal
{
static Random rand = new Random();

public static double sndRNG()
{
double x = rand.NextDouble();
double y = rand.NextDouble();
return Math.Sqrt(-2.0 * Math.Log(x)) * Math.Cos(Math.Pi * y);
}
}

class App
{
public static int Main()
{
Console.WriteLine(Normal.sndRNG());
}
}
 
Jon said:
Thanks for all the suggestions, I tried all of them but I am still getting
the same numbers each time. When the user presses the button I have it for
testing so that I can see the values the application generated in a label.
With one press, all of the numbers are the same. With successive presses we
get different numbers, but not with the single press. Here is a larger
chunk of code:

.... code snipped ...

I tried your code here, and I'm not seeing 'the same numbers each time',
but then I'm not sure exactly what I'm supposed to look at, and I had to
fill in a bit of code to get your sample to compile (making assumptions
along the way).

I suggest you post a small, complete *console* application that someone
can just compile at the command line (or paste in one shot into VS.NET)
that shows the problem you're running into now.

I'd point you to Jon Skeet's page about samples to repro problems, but
his site seems to be unavailable at the moment.
 
mikeb said:
I suggest you post a small, complete *console* application that someone
can just compile at the command line (or paste in one shot into VS.NET)
that shows the problem you're running into now.

Hear hear :)
I'd point you to Jon Skeet's page about samples to repro problems, but
his site seems to be unavailable at the moment.

Mmm, it does, doesn't it? Then again, I can't get to Slashdot either...

Anyway, when it's back up, it's at

http://www.pobox.com/~skeet/csharp/complete.html

Until that time, here's the google cache of it:
http://tinyurl.com/rx28
 
Hi guys,
Thanks for the suggestions. It turns out the problem was something really
silly in another part of the program. I posted that stuff after a long
period spent with the computer, sometimes it's just best to leave it alone
for a bit and come back to it. In any case, everythings fixed and thanks
again for the suggestions.
 
Jon Agiato said:
Hi guys,
Thanks for the suggestions. It turns out the problem was something really
silly in another part of the program. I posted that stuff after a long
period spent with the computer, sometimes it's just best to leave it alone
for a bit and come back to it. In any case, everythings fixed and thanks
again for the suggestions.

You might try the method below. It's considerably faster (only 2 calls to
System.Random instead of 16) but still returns Gaussian normal results.

double Normal()
{
return Math.Sqrt(-2.0 * Math.Log(rand.NextDouble())) * Math.Cos(Math.PI
* rand.NextDouble());
}
 
Back
Top