Hi. I'm new to C# and i'm facing this wierd thing. To put it simple i have two classes:

- Especimen
- Form1

Form1 has a button, when you click it it generates 10 objects of class Especimen. This is a very simple class, it's supposed to simulate a biological particle so, besides other irrelevant properties, it has an integer that indicates how old will it "die".
Through a textBox I indicate the "more or less" age i want them to die but i don't want them to die at the same time that's why i call this function from Especimen's constructor:

private int CalcularEdadFinal(int eF)
        {
            Random randNum = new Random();
            diferencia = randNum.Next(0, 10);
            if (diferencia % 2 == 0) return eF - diferencia;
            else return eF + diferencia;
        }

Easy! This will generate a number between 0 and 10 so when i say i want them to die at "more or less" 40 cicles, they will be dying when they are between 30 and 50 cicles, so it's more "natural" than dying all at the same time, right? OK!

This is the button1_click function:

private void button2_Click(object sender, EventArgs e)
        {
            iMaximoEspecimenes = int.Parse(tbMaximoEspecimenes.Text);
            iMediaMortalidad = int.Parse(tbMediaMortalidad.Text);

            List<Especimen> listaEspecimenes = new List<Especimen>();
            for (int i = 0; i < iMaximoEspecimenes; i++)
            {
                listaEspecimenes.Add(new Especimen(iMediaMortalidad));
            }
            foreach (Especimen especimen in listaEspecimenes)
            {
                MessageBox.Show("Especimen nº " + listaEspecimenes.IndexOf(especimen) + "\n\nMorirá a los " + especimen.EdadFinal + " ciclos.\nPoblacion: " + Especimen.Poblacion + ".");
            }
        }
        }

That's the code. When i run it, ALL objects have the same dying age, so weird. So I added a breakpoint in the function that generates the dying age and guess what, it works perfectly when debugging but not in a normal run. So it's like the function doesn't have enough time to generate different values everytime the constructor calls it (10 times in a row) but it does have the time to generate different values if i'm debugging the program (going instruction by instruction).

It also works fine if i add a MessageBox.Show("bla") in the for that fills the list with 10 objects, also giving time the generator to generate different numbers and not the same one everytime.

How can i fix this? Why does it seems to not work properly when working without stopping everytime i call this function?

Thank you! I hope i made this clear to read and solution, excuse my english.

Recommended Answers

All 8 Replies

When i run it, ALL objects have the same dying age, so weird. So I added a breakpoint in the function that generates the dying age and guess what, it works perfectly when debugging but not in a normal run. So it's like the function doesn't have enough time to generate different values everytime the constructor calls it (10 times in a row) but it does have the time to generate different values if i'm debugging the program (going instruction by instruction).

How can i fix this? Why does it seems to not work properly when working without stopping everytime i call this function?

I think your problem is in here:

private int CalcularEdadFinal(int eF)
{
  Random randNum = new Random();
  diferencia = randNum.Next(0, 10);
  if (diferencia % 2 == 0) return eF - diferencia;
  else return eF + diferencia;
}

Every time you're getting a new final age, you're creating a new Random object. You're on the right track; the Random classes are getting created fast enough that each Random object gets the same seed, and therefore generates the same random numbers.

The MSDN documentation for Random says: "The default seed value is derived from the system clock and has finite resolution. As a result, different Random objects that are created in close succession by a call to the default constructor will have identical default seed values and, therefore, will produce identical sets of random numbers."

The solution to your problem is to only create one Random object outside of your calculating method, and just use it multiple times, maybe like this:

Random randNum = new Random();

private int CalcularEdadFinal(int eF)
{
  diferencia = randNum.Next(0, 10);
  if (diferencia % 2 == 0) return eF - diferencia;
  else return eF + diferencia;
}

I hope i made this clear to read and solution, excuse my english.

It was plenty clear; no pasa na' :).

Thank you very much. I was using Thread.Sleep(10) while waiting for your solution hahaha

Now it seems to work good. Gracias de nuevo!

Hi.. i know this was kinda solved but actually it is not. I realized that there exist some patterns.
Usually the results I get are like this: 16,16,19,25,25,21,18,15,15,23,23... so it's more or less random although you get to see that sometimes it doesn't have enough time to generate and there are some couples that are the same number.
I added a recursive function in one of the places that calls for this generation to occur so now it calls more often and i get things like: 25,25,25,25,25,25,25,25,19,19,19,19,19,19,19...

The line that creates the random object is out of the function so the only thing that gets called over and over again is the Next() function.

How to fix this?

Thank you.

randNum.Next(0, 10); returns an integer between 0 and 10 inclusive.
You will only get one of 11 possibilites.
Maybe you should think about increasing the range or using the NextDouble method instead.

Usually the results I get are like this: 16,16,19,25,25,21,18,15,15,23,23... so it's more or less random although you get to see that sometimes it doesn't have enough time to generate and there are some couples that are the same number.

"Doesn't have enough time" isn't correct here... that concept applies only when you're creating new Random objects. As Nick pointed out, you're not getting a wide range of random numbers, so it's normal that it would occasionally come up with the same one twice in a row. There's nothing wrong here.

I added a recursive function in one of the places that calls for this generation to occur so now it calls more often and i get things like: 25,25,25,25,25,25,25,25,19,19,19,19,19,19,19...

This is unusual. Could you post code for the recursive method?

This function is generating the number:

Random randNum = new Random();
        private int CalcularEdadFinal(int eF)
        {
            //Thread.Sleep(10);
            
            diferencia = randNum.Next(0, 10);
            if (diferencia % 2 == 0) return eF - diferencia;
            else return eF + diferencia;
        }

But the user gets to enter an initial value. So if I say 60, i'll get any result from 50 to 70, because the program will take that initial 60 and then add or take any value from 0 to 10.

This is the recursive thing:

private void CrearEspecimenes()
        {

            /* lot of irrelevant code*/

            int repetir = nacimiento.Next(0, 2);
            if (repetir == 1 && Especimen.Poblacion < iMaximoEspecimenes)
            {
                CrearEspecimenes();
            }

That CrearEspecimenes() function what does is checks the born probability value input by the user and runs a random value from 0 to 100. If this number is equal or below the user input (if it "hits" on the chances) then the specimen is born.

Untill here the program worked perfectly to my objectives. But then i wanted to improve this birth part because it's only executed each time the clock ticks (frequency is also set by the user, but all the tests are doing it at each 200ms calls CrearEspecimenes() and see if a birth goes on or not).
So every tick it can only born 1 or 0 specimen so i thought i could do the recursive thing to change that. It will run a coin flip (dunno why Next(0, 1) didn't work so i made it Next(0, 2)), if it hits (repetir == 1) and we are not overpopulated yet (Especimen.Poblacion < iMaximoEspecimenes) then it will call itself.

I know this code must seem weird and i do still write spaguetti code but i'm working on it guys :P

Next(0, 1) does not give 1 very often because the random generator rounds its internal double value to the range given (i.e 0.99 would still return 0).
When using Random I generally use NextDouble and do the ranging myself. That way I can round up or down depending upon my needs.
So to get a 50:50 split I would use if (randNum.NextDouble() < 0.5) .

Also, I just noticed that you do not get the full +/- 10 around your end time.
Because of the if (diferencia % 2 == 0) you only get even number below eF and odd numbers above eF.
Try using:

Random randNum = new Random();
private int CalcularEdadFinal(int eF)
{
    return eF + randNum.Next(0, 20) - 10;
}

Did not read the whole thread, but about the Next(0, 1), if you read the intellisense documentation, you should notice that the second parameter (the 1, in this case) is the *exclusive* upperbounds. You are in essence asking for a random integer between 0 and 0. If you want 0 or 1, then Next(0, 2) is the way to go, as you have discovered.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.