PHP shuffle函数使用的算法

时间:2010-11-12 07:17:40

标签: php

php shuffle函数使用的算法是什么,或者我在哪里可以得到它的代码。我必须用C语言实现它。我已经在C中实现了fisher yates算法,但是php shuffle函数显示效果不佳。

1 个答案:

答案 0 :(得分:5)

究竟什么构成“不好结果”?

Fisher-Yates shuffle将以相同的概率生成所有排列,但仅当您正确生成随机数时。这里有三个问题需要注意。首先,您需要一个好的伪随机数生成器。 C标准库rand通常不是一个好的PRNG(尽管它取决于您的C库实现)。如果您使用的是POSIX平台,请考虑使用lrand48。您的系统可能有其他RNG。如果你的平台上没有任何东西,那么非常小的代码中的一个非常好的RNG是G. Marsaglias KISS生成器 - 你可以找到代码here。其次,如果您仍然决定使用rand,请注意它会生成介于0和RAND_MAX之间的随机数。对于大量实现,RAND_MAX仅为32767,因此如果rand() % count大于32768,则通常的count会产生非常明显和不良的偏差。第三,rand() % count(或lrand48() % count或类似的东西)实际上也是一个坏主意,因为它也引入了偏见。如果count不是2的幂,则某些数字的概率高于其他数字。而且,在许多发生器中,低阶位比高阶位少得多。您可以尝试使用(long long) rand() * count / RAND_MAX或类似的东西解决此问题,但实际上您最好使用优质的RNG。

在0(包括)和k(不包括)之间生成无偏随机数的正确方法是:首先,获得一个适当的PRNG,为您提供足够大的随机数(比如32个随机位)。然后减少到大于k的下一个2的幂。最后,如果该值大于或等于k,请再试一次。这是一种完全无偏见的方法,并且会给出与PRNG一样好的结果。代码看起来像这样:

static unsigned int random(unsigned int k)
{
  // You can get rid of this loop using bit tricks, but I keep it for clarity     
  unsigned int n, nextpow2 = 1;
  while (nextpow2 < k) 
    nextpow2 *= 2;

  do {
    n = random32() & (nextpow2 - 1); // random32 is your 32-bit RNG
  } while (n >= k);

  return n;
}