8

All I want is a pragmatic random number generator in C# so I can say e.g.

int dummyAge = MathHelpers.GetRandomNumber(20,70);

and have it seem quasi random, e.g. to generate dummy data.

Most stack overflow questions on this topic and on the web get into a philosophical discussions on true randomness which is not what I'm interested at the moment, e.g. I did one in PHP a long time ago which uses milliseconds/sleep which is fine for dummy data, I'm just trying to do this in C# quick.

Does anyone have a quick half-decent C# random number generator based on some time seed, etc. or, how could I change the following code so that it always doesn't generate the same 5 number in a row?

using System;

namespace TestRandom23874
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("the random number is: {0}", MathHelpers.GetRandomNumber(1, 10));
            Console.WriteLine("the random number is: {0}", MathHelpers.GetRandomNumber(1, 10));
            Console.WriteLine("the random number is: {0}", MathHelpers.GetRandomNumber(1, 10));
            Console.WriteLine("the random number is: {0}", MathHelpers.GetRandomNumber(1, 10));
            Console.WriteLine("the random number is: {0}", MathHelpers.GetRandomNumber(1, 10));
            Console.ReadLine();
        }
    }

    public class MathHelpers
    {
        public static int GetRandomNumber(int min, int max)
        {
            Random random = new Random();
            return random.Next(min, max);
        }
    }
}
Community
  • 1
  • 1
Edward Tanguay
  • 189,012
  • 314
  • 712
  • 1,047
  • I think you mean "pseudo-random". Quasi-random means something else. – John D. Cook Jun 26 '09 at 01:35
  • I think quasi ("as if, as though, as it were, in a manner sense or degree, having some resemblance to") is more fitting in this sense than pseudo ("not genuine but having the appearance") since they are genuine random numbers to the average user, but they are random numbers to a mathematician "only in a matter or degree". – Edward Tanguay Jun 28 '09 at 12:47

2 Answers2

13
public class MathHelpers
    {
        private static Random random = new Random();
        public static int GetRandomNumber(int min, int max)
        {
            return random.Next(min, max);
        }
    }

This way, you're not creating a new Random object every time, rather you're reusing the same one. When you recreate a new one quickly enough, they will yield the same results. If however, you reuse an existing one, you'll get randomness.

BFree
  • 102,548
  • 21
  • 159
  • 201
  • 1
    Note : This is true for C# but also in many others languages (C, C++, Java, ...). You usually seed your RNG once, and reuse it as long as you need it. I can't remember how many times i saw people asking help on dev-related forums because they kept re-seeding their RNG. – Ksempac Jun 25 '09 at 14:49
  • Nope, it isn't, since the Next method isn't static and the MSDN doc on Random tells you only public static members are thread-safe. – Ksempac Jun 25 '09 at 15:01
2

BFree's answer is fine, but I think it's also worth mentioning a slightly different pattern - passing the Random instance into anything that needs it, rather than always using a single instance via a static variable. The downside of the latter approach is that Random isn't thread-safe. You either need some locking, or thread-local variables, or avoiding using multiple threads to start with. So I would adjust the original code in the question to:

using System;

namespace TestRandom23874
{
    class Program
    {
        static void Main(string[] args)
        {
            Random rng = new Random();
            Console.WriteLine("the random number is: {0}", 
                MathHelpers.GetRandomNumber(rng, 1, 10));
            Console.WriteLine("the random number is: {0}", 
                MathHelpers.GetRandomNumber(rng, 1, 10));
            Console.WriteLine("the random number is: {0}", 
                MathHelpers.GetRandomNumber(rng, 1, 10));
            Console.WriteLine("the random number is: {0}", 
                MathHelpers.GetRandomNumber(rng, 1, 10));
            Console.WriteLine("the random number is: {0}", 
                MathHelpers.GetRandomNumber(rng, 1, 10));
        }
    }

    public class MathHelpers
    {
        public static int GetRandomNumber(Random random, int min, int max)
        {
            return random.Next(min, max);
        }
    }
}

It's just basic inversion of control, really. You might have one static RNG with locking round it, used to generate a new instance of Random in a thread-safe way when you need it (by randomly generating a seed and then using that to create the instance) then reusing the Random throughout a particular single-threaded set of operations.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194