要随机排列列表,必须选择其中之一可能性,这很快超出了传统 PRNG 的能力。即使 Mersenne Twister 的列表长度超过 2080 个条目也会失败,并且在实践中可能会失败得更快,因为不能保证以消除重复结果的方式使用它的状态。
因此,在设计算法以将列表从不充分状态中洗牌并将其设计为库函数(而不是特定于应用程序的解决方案)的过程中,通常应该满足(或最大化或最小化)首先,什么妥协可能是最良性的?
这是一般情况。显然,某些应用程序忽略了其他应用程序可能会导致灾难性故障的问题。
换句话说,当你事先知道它一定是不完美的(就像你知道 PRNG 是不完美的一样)时,你如何评估洗牌的质量?
我问的原因,作为我想检测的各种事情的一个例子,是在开发洗牌算法的过程中,我得到了一些明显不好的结果,但不确定将它们形式化的最佳方法是什么就像测试一样。
例如,一个严重有问题的洗牌是:
static uint32_t n; // number of elements in list to shuffle
static uint32_t m; // n rounded up to a power-of-two, minus one
static uint32_t state; // set to a random value to randomise order
void shuffle_seed(uint32_t seed) {
state = s;
}
uint32_t next_index(void) {
do {
seed = (state * 1103515245 + 12345) & m;
} while (state >= n);
return state;
}
您可以调用此函数n时间并保证和之间的n唯一结果......所以这是一个排列;但是当您将一个种子的结果与另一个种子的结果进行比较时,您会发现它们是从不同点开始的相同序列。此外,每隔一个索引都是奇数,其他索引是偶数。0n
另一种稍微高级的设计给出了部分子字符串匹配,而不是整个匹配。
如果只能选择要么(对于小) 的不同排列,包含相似子字符串的可能是您首先要消除的。我预计还有许多其他我没有想到的糟糕选择。