您正在寻找什么样的建议?效率?正确性?你确实提到了单元测试......我认为那里肯定会有改进。
我实际上帮助开发了一款在线游戏及其洗牌机制。我真的不怀疑性能是一个很大的问题,因为您发现的大多数算法大体上都是相同的。但是,我会建议以下内容,
一个。创建随机界面
public interface IRandom
{
byte NextRandomByte ();
}
现在使用此接口的任何东西现在都可以在受控方式或环境中进行模拟\单元测试。您并不是真的想对真正随机的算法进行单元测试——您将无法验证您的数据!
至于为什么要返回一个字节,一个字节可能是你想要的最小随机单位。不仅如此,如果给定一种生成单个随机字节的方法,生成它们的序列并将它们连接在一起是一种生成更广泛随机数据的简单方法。
当然,您必须警惕在数据中引入偏见......
b.通过减少任意间隔的偏差来确保数据质量。假设基础数据是均匀随机的,任何不是 256 倍的区间都会引入偏差。考虑一下,
// 250 is not a factor of 256!
byte a = random.NextRandomByte () % 250; // values 0-5 are biased!
在前面的 sn-p 中,值 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;
}
c。消耗!将您的算法或助手放在无状态扩展或静态类中,例如
// 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);
显然,前面的所有内容都是可选的,但有助于单元测试并提高随机数据的整体质量。
一般来说,随机和“公平”的骰子是一个非常有趣的话题。如果您有兴趣,我强烈建议您找个时间谷歌一下并进行一些研究。 :)