What offers are you looking for exactly? efficiency? correctness? You are talking about one unit testing ... I think there might be an improvement.
I really helped develop an online game and a mechanism for shuffling them. I really don't suspect that performance is a big problem, since most of the algorithms you find are basically the same. I would suggest the following,
a. create a random interface
public interface IRandom { byte NextRandomByte (); }
Everything that now consumes this interface can now mock the module \ in a controlled way or environment. You really do not want to be a unit test of truly random algorithms - you will not be able to verify your data!
In order to return a byte, a byte is probably the smallest unit of randomness you might want. Not only this, but also subject to the creation of one random byte, generating a sequence of them and combining them together is an easy way to create an even wider range of random data.
Of course, you will need to be careful to bias your data ...
b. Ensuring data quality by reducing bias during arbitrary intervals. Assuming that the underlying data is uniformly random, any interval that is NOT a factor of 256 will lead to bias. Consider this,
In the previous fragment, values 0-5 have a probability of occurrence of 2/255, and values 6-249 have a probability of 1/255. This is a significant bias over time. One approach is to check the number coming from the generator and discard it if it exceeds the allowable range
// continually generate random data until it is satisfactory for (byte r = random.NextRandomByte (); r > 250; r = random.NextRandomByte ()) { } byte a = r % 250; // r is guaranteed to be on [0, 250], no longer bias
The "valid range" can be determined by finding the largest multiple of your interval, which can be represented by your value type. More generalized form
byte modulo; // specified as parameter byte biasThreshold = (byte.MaxValue / modulo) * modulo; for (; unbiasedValue >= biasThreshold; ) { // generate value unbiasedValue = random.NextRandomByte (); }
And if you need values greater than a byte, just combine the values together,
int modulo;
with. Consume! Put your algorithms or helpers in non-static extensions or static classes like
// forgive my syntax, recalling from memory public static class IRandomExtensions { public int GetUnbiasedInteger (this IRandom random, int modulo) { } public int GetUnbiasedUnsignedInteger (this IRandom random, uint modulo) { } public int GetUnbiasedLong (this IRandom random, long modulo) { } public int GetUnbiasedUnsignedLong (this IRandom random, ulong modulo) { } ... } public static class IEnumerableExtensions { public IEnumerable<T> Shuffle<T>(this IEnumerable<T> items, IRandom random) { // shuffle away! ... } }
The decision on whether to implement them as methods on your interface or as external methods [as I did] is up to you, but keep in mind that their member methods force developers to repeat or duplicate the code. Personally, I like extensions. They are very clean. And sexy.
int randomNumber = random.UnbiasedInteger (i - 1); List<int> shuffledNumbers = numbers.Shuffle (random);
Obviously, all of the previous ones are optional, but facilitate unit testing and improve the overall quality of your random data.
Random and honest bones are a very interesting topic in general. If you are interested at all, I highly recommend you one day and do some research. :)