【问题标题】:How random is PHP's shuffle function?PHP 的 shuffle 函数有多随机?
【发布时间】:2011-08-07 08:23:55
【问题描述】:

有谁知道 PHP 的 shuffle() 函数的随机性是什么?它取决于操作系统吗? 它是否使用 PHP 自己的播种机?

是否可以使用mt_rand() 作为生成器?

【问题讨论】:

  • 它对于大多数应用程序来说足够随机。但它在密码学上并不安全。

标签: php random shuffle


【解决方案1】:

shuffle()函数基于与rand()相同的生成器,即基于linear congruential algorithm的系统生成器。这是一个快速生成器,但或多或​​少具有随机性。自 PHP 4.2.0 起,随机生成器是自动播种的,但您可以根据需要使用srand() 函数来播种。

mtrand() 基于Mersenne Twister algorithm,这是可用的最佳伪随机算法之一。要使用该生成器对数组进行随机播放,您需要编写自己的随机播放函数。例如,您可以查看Fisher-Yates algorithm。编写自己的 shuffle 函数会产生更好的随机性,但会比内置的 shuffle 函数慢。

【讨论】:

    【解决方案2】:

    根据 Mirouf 的回答(非常感谢您的贡献)...我对其进行了一些改进以消除冗余数组计数。为了我自己的理解,我对变量的命名也略有不同。

    如果你想像 shuffle() 一样使用它,你可以修改要通过引用传递的参数,即 &$array,然后确保将 return 更改为简单的:“return;”并将生成的随机数组分配回 $array ,如下所示: $array = $randArr; (返回前)。

    function mt_shuffle($array) {
        $randArr = [];
        $arrLength = count($array);
    
        // while my array is not empty I select a random position
        while (count($array)) {
            //mt_rand returns a random number between two values
            $randPos = mt_rand(0, --$arrLength);
            $randArr[] = $array[$randPos];
    
            /* If number of remaining elements in the array is the same as the
             * random position, take out the item in that position,
             * else use the negative offset.
             * This will prevent array_splice removing the last item.
             */
            array_splice($array, $randPos, ($randPos == $arrLength ? 1 : $randPos - $arrLength));
        }
    
        return $randArr;
    }
    

    【讨论】:

      【解决方案3】:

      PHP 7.1 更新

      由于rng_fixes rfc 是为 PHP 7.1 实现的,shuffle 的实现现在使用 Mersenne Twister PRNG(即它使用 mt_rand 并受到调用 mt_srand 的影响)。

      旧系统 PRNG (rand) 不再可用; randsrand 函数实际上是它们的 mt_ 等效项的别名。

      【讨论】:

        【解决方案4】:

        rand()一样是随机的;

        而且作为 PHP 风格,您不需要播种

        【讨论】:

          【解决方案5】:
          mt_rand()
          

          生成一个随机数。

          shuffle()
          

          随机化一个数组。它还会在数组中生成新键,而不仅仅是重新排列旧键。

          如果你想在 PHP 中播种,你会使用 mt_strand()

          但是,由于 PHP 4.2.0 播种是在您调用 mt_rand 时在 PHP 中自动完成的。

          【讨论】:

          • 那么,基本上如果你想使用 mt_rand() 作为你的生成器,你必须滚动你自己的 shuffle() 函数吗?或者如果 mt_rand() 已经被使用过,shuffle 使用它吗?
          【解决方案6】:

          适用于关联数组和数值数组:

          function mt_shuffle_array($array) {
              $shuffled_array = [];
              $arr_length = count($array);
          
              if($arr_length < 2) {
                  return $array;
              }
          
              while($arr_length) {
                  --$arr_length;
                  $rand_key = array_keys($array)[mt_rand(0, $arr_length)];
          
                  $shuffled_array[$rand_key] = $array[$rand_key];
                  unset($array[$rand_key]);
              }
          
              return $shuffled_array;
          }
          
          $array = [-2, -1, 'a' => '1', 'b' => '2', 'c' => '3', 11, 'd' => '4', 22];
          $shuffled_array = mt_shuffle_array($array);
          

          【讨论】:

            【解决方案7】:

            我创建了一个随机排序数组的函数。

            /**
             * Build a random array
             *
             * @param mixed $array
             *
             * @return array
             */
            function random_array($array) {
                $random_array = array();
                // array start by index 0
                $countArray = count($array) - 1;
            
                // while my array is not empty I build a random value
                while (count($array) != 0) {
                    //mt_rand return a random number between two value 
                    $randomValue = mt_rand(0, $countArray);
                    $random_array[] = $array[$randomValue];
            
                    // If my count of my tab is 4 and mt_rand give me the last element, 
                    // array_splice will not unset the last item
                    if(($randomValue + 1) == count($array)) {
                        array_splice($array, $randomValue, ($randomValue - $countArray + 1));
                    } else {
                        array_splice($array, $randomValue, ($randomValue - $countArray));
                    }
            
                    $countArray--;
                }
            
                return $random_array;
            }
            

            这不是最好的方法,但是当我使用函数 shuffle 时,它​​总是以相同的顺序返回一个随机数组。如果这可以帮助某人,我会很高兴!

            【讨论】:

            • 您应该使用 array_splice 并在每次迭代时更新 countArray。未设置会在数组中留下空白,如果您随机选择已取消设置的索引之一,您将在输出数组中添加一个 NULL。
            猜你喜欢
            • 2012-12-15
            • 1970-01-01
            • 1970-01-01
            • 2021-05-09
            • 2012-08-09
            • 2011-08-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多