views:

105

answers:

2

I am wanting to generate a random array of sequences that repeat and only use each number once. For example, given a range of 0-9 with 2 different seeds you might get

Seed 1: 7 3 5 9 0 8 1 2 6 4 | 7 3 5 9 0 8 1 2 6 4 | 7 3 5 9 0 8 1 2 6 4
Seed 2: 2 5 7 1 4 9 6 8 3 0 | 2 5 7 1 4 9 6 8 3 0 | 2 5 7 1 4 9 6 8 3 0

From what I understand, a Linear Congruential Random Number Generator or LCRNG or LCG can give me this http://en.wikipedia.org/wiki/Linear_congruential_generator

Any idea if an implementation exists in C# or how I would get started with writing one.

How does a Mersenne Twister differ from an LCG?

Not sure all of my questions are answered, but here is what I ended up using. Because I am bounding the sample size to the range of values from max to min, I am selecting a different prime number that stays static as long as the same initial seed is given. I do this because I want the same sequence given the same seed and the same min/max bounds for repeatability of testing.

Please critique anything I do here, this is just what I came up with in a jiffy:

using System;
using System.Collections.Generic;

namespace FULLCYCLE
{
    public class RandomNumber
    {
        private int _value;
        private int _prime;
        private static List<int> primes = new List<int>()
        {
            11,
            23,
            47,
            97,
            797,
            1597,
            6421,
            25717,
            51437,
            102877,
            411527,
            823117,
            1646237,
            3292489,
            6584983,
            13169977,
            26339969,
            52679969,
            105359939,
            210719881,
            421439783,
            842879579,
            1685759167
        };

        public RandomNumber( int seed )
        {
            _prime = primes[seed%primes.Count];
            _value = seed;
        }

        public int Next( int min, int max )
        {
            int maxrate = (max-min+1);
            if (_value > maxrate)
            {
                _value = _value % maxrate;
            }

            _value = (_value + _prime) % maxrate;
            return _value + min;
        }
    }
}
+1  A: 

Why not just use the existing Random class and a Knuth shuffle on your input sequence?

Ron Warholic
From what I understand of the Knuth shuffle, if I wanted random numbers between 0 and 1 billion, then I would need to store this whole array in memory and shuffle it in memory. With an LCG it seems I can accomplish the same with very little memory.
esac
The LCG will also not guarantee that the numbers do not repeat. You could get 100 five times in a row depending on your seed. Without knowing what numbers have already been yielded how do you expect to generate each number only once?
Ron Warholic
@Ron: If you setup the input parameters of the LCG correctly then you are guaranteed that it will generate all possible numbers in the range before repeating itself.
LukeH
@LukeH- as shown by http://en.wikipedia.org/wiki/Full_cycle (which ironically includes C# code to do what the OP would like). However this requires constraints on the seed and sample size (if the increment prime divides the sample size you will get repeats).
Ron Warholic
A: 

Regarding your edit, there are several problems with your LCG as a random number generator...

  1. It can produce obvious patterns:

    // generates 3, 4, 5, 6, 7, 8, 9, 0, 1, 2
    var rng = new RandomNumber(42);
    for (int i = 0; i < 10; i++) Console.WriteLine(rng.Next(0, 9));
    
  2. It can repeat itself:

    // generates 579, 579, 579, 579, 579, 579, 579, 579, 579, 579
    var rng = new RandomNumber(123);
    for (int i = 0; i < 10; i++) Console.WriteLine(rng.Next(456, 51892));
    

There are many other seed/min/max combinations that will generate problematic results.

LukeH