PHP shuffle函数使用的算法

PHP shuffle函数使用的算法,php,Php,php shuffle函数使用的算法是什么,或者在哪里可以获得它的代码。我必须用C语言实现它。我已经用C语言实现了fisher-yates算法,但并没有像php shuffle函数所显示的那样得到很好的结果。到底是什么构成了“不好的结果” Fisher-Yates洗牌将以相同的概率生成所有排列,但前提是正确生成随机数。这里有三个问题需要注意。首先,您需要一个好的伪随机数生成器。C标准库rand通常不是一个好的PRNG(尽管它取决于您的C库实现)。如果您在POSIX平台上,请考虑使用 LRAND4

php shuffle函数使用的算法是什么,或者在哪里可以获得它的代码。我必须用C语言实现它。我已经用C语言实现了fisher-yates算法,但并没有像php shuffle函数所显示的那样得到很好的结果。

到底是什么构成了“不好的结果”

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

生成0(包括)和
k(排除)之间的无偏随机数的正确方法是:首先,获得一个适当的PRNG,该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;
}
static unsigned int random(unsigned int k)
{
//你可以使用一些小技巧来摆脱这个循环,但为了清晰起见,我保留了它
无符号整数n,nextpow2=1;
while(nextpow2=k);
返回n;
}
什么是“不好的结果”

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

生成0(包括)和
k(排除)之间的无偏随机数的正确方法是:首先,获得一个适当的PRNG,该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;
}
static unsigned int random(unsigned int k)
{
//你可以使用一些小技巧来摆脱这个循环,但为了清晰起见,我保留了它
无符号整数n,nextpow2=1;
while(nextpow2=k);
返回n;
}