Какие именно предложения вы ищете? эффективность? правильности? Вы упоминаете юнит-тестирование ... Я думаю, что там определенно может быть улучшение.
Я на самом деле помогал в разработке онлайн-игры и механизма их перетасовки. Я не подозреваю, что производительность является большой проблемой, так как большинство алгоритмов, которые вы найдете, в основном одинаковы. Однако я бы предложил следующее:
а. создать случайный интерфейс
public interface IRandom
{
byte NextRandomByte ();
}
Все, что теперь использует этот интерфейс, теперь может быть смоделировано \ проверено модулем контролируемым образом или в определенной среде. Вы действительно не хотите проводить модульное тестирование действительно случайных алгоритмов - вы не сможете проверить свои данные!
Что касается того, зачем возвращать байт, байт, вероятно, является наименьшей единицей случайности, которую вы могли бы хотеть. И не только это, но при наличии средства генерации одного случайного байта, генерация последовательности из них и объединение их вместе - это простой способ генерирования еще более широкого диапазона случайных данных.
Конечно, вам нужно с осторожностью относиться к предвзятости в ваших данных ...
б. Гарантируйте качество данных, уменьшая смещение через произвольные интервалы. Предполагая, что лежащие в основе данные являются равномерно случайными, любой интервал, который НЕ является фактором 256, приведет к смещению. Учтите это,
// 250 is not a factor of 256!
byte a = random.NextRandomByte () % 250; // values 0-5 are biased!
В предыдущем фрагменте значения 0-5 имеют вероятность 2/255, а значения 6-249 - 1/255. Это значительный уклон с течением времени. Один из подходов заключается в проверке числа, поступающего от генератора, и отбрасывании его, если оно превышает допустимый диапазон
// 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
«Приемлемый диапазон» может быть определен путем нахождения наибольшего кратного вашего интервала, который может быть представлен вашим типом значения. Более обобщенная форма
byte modulo; // specified as parameter
byte biasThreshold = (byte.MaxValue / modulo) * modulo;
for (; unbiasedValue >= biasThreshold; )
{
// generate value
unbiasedValue = random.NextRandomByte ();
}
А если вы хотите, чтобы значения были больше байта, просто объедините значения вместе,
int modulo; // specified as parameter
int biasThreshold = (int.MaxValue / modulo) * modulo;
for (; unbiasedValue >= biasThreshold; )
{
// generate value
byte a = random.NextRandomByte ();
byte b = random.NextRandomByte ();
...
int unbiasedValue = a << 24 + b << 16 + c << 8 + d;
}
с. Потребляйте! Поместите свои алгоритмы или помощники в классы расширений без сохранения состояния или статические, например
// 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!
...
}
}
Решение о том, следует ли реализовывать их как методы в вашем интерфейсе или как внешние методы [как я это сделал], остается за вами - но имейте в виду, что их методы-члены заставляют разработчиков повторять или дублировать код. Лично мне нравятся расширения. Они очень чистые. И сексуально.
int randomNumber = random.UnbiasedInteger (i - 1);
List<int> shuffledNumbers = numbers.Shuffle (random);
Очевидно, что все вышесказанное является необязательным, но облегчает модульное тестирование и улучшает общее качество ваших случайных данных.
Случайные и «честные» кости - очень интересная тема в целом. Если вас это вообще заинтересовало, я настоятельно рекомендую вам это сделать в Google и провести некоторое исследование. :)