Reputation: 24685
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;
}
}
}
Upvotes: 2
Views: 7345
Reputation: 87
Try the following code:
namespace System
{
/// <summary>
/// Represents a pseudo-random number generator using the linear congruential method:
/// X[i+1] = (a • X[i] + c) % m (where i is greater than or equal to 0).
/// </summary>
public class LinearCongruentialRandom : Random
{
private int _x = 1971111612;
private int _a = 2147483629;
private int _c = 2147483587;
private int _m = 2147483647;
/// <summary>
/// Initializes a new instance of <see cref="LinearCongruentialRandom"/> with default values.
/// </summary>
public LinearCongruentialRandom()
{
= base.Next(0, _m);
}
/// <summary>
/// Initializes a new instance of <see cref="LinearCongruentialRandom"/> with default values.
/// </summary>
public LinearCongruentialRandom(int seed)
{
if (seed >= _m) throw new ArgumentOutOfRangeException(nameof(seed), seed, null);
_x = seed;
}
/// <summary>
/// Initializes a new instance of <see cref="LinearCongruentialRandom"/> with the specified parameters.
/// </summary>
/// <param name="seed">Initial seed value less than m.</param>
/// <param name="a">A multiple of p for every prime p that is a divisor of m.</param>
/// <param name="c">Increment c. The numbers c and m must be relatively prime.</param>
/// <param name="m">The length of the repetition period m. The numbers c and m must be relatively prime.</param>
public LinearCongruentialRandom(int seed, int a, int c, int m) : this(seed)
{
_a = a;
_c=c;
_m=m;
}
/// <inheritdoc cref="Random.Next()"/>
public override int Next()
{
return _x = (_a * _x + _c) % _m;
}
/// <inheritdoc cref="Random.NextBytes(byte[])"/>
public override void NextBytes(byte[] buffer)
{
if (buffer == null)
throw new ArgumentNullException(nameof(buffer));
unchecked
{
for (int index = 0; index < buffer.Length; ++index)
buffer[index] = (byte)Next();
}
}
}
}
Upvotes: 0
Reputation: 269388
Regarding your edit, there are several problems with your LCG as a random number generator...
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));
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.
Upvotes: 1
Reputation: 10074
Why not just use the existing Random
class and a Knuth shuffle on your input sequence?
Upvotes: 1