#18401 [Opn->Fbk]: shuffle() broken
| From: | kalowsky@php.net | Date: | Sun, 11 Aug 2002 06:30:52 +0000 |
| Subject: | #18401 [Opn->Fbk]: shuffle() broken | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-16478@lists.php.net to get a copy of this message | ||
ID: 18401
Updated by: kalowsky@php.net
Reported By: adam@trachtenberg.com
-Status: Open
+Status: Feedback
Bug Type: Arrays related
Operating System: Redhat 7.3
PHP Version: 4CVS-2002-07-18
New Comment:
I'm pretty Brad has been playing with this code. Can you test again,
and report back with a new snapshot?
Previous Comments:
------------------------------------------------------------------------
[2002-07-18 01:03:51] adam@trachtenberg.com
The shuffle() function in the CVS is (still) broken. It does not
correctly generate all possible combinations of the array. (I know this
function was recently updated, this test is with new version.)
Here is a diff to fix the problem:
--- array.c Thu Jul 18 00:50:54 2002
+++ array.new.c Thu Jul 18 00:49:35 2002
@@ -1441,7 +1441,7 @@
{
Bucket **elems, *temp;
HashTable *hash;
- int j, n_elems, cur_elem = 0, rnd_idx, n_left;
+ int j, n_elems, rnd_idx, n_left;
n_elems = zend_hash_num_elements(Z_ARRVAL_P(array));
@@ -1457,13 +1457,12 @@
elems[j++] = temp;
while (--n_left) {
rnd_idx = php_rand(TSRMLS_C);
- RAND_RANGE(rnd_idx, cur_elem, n_left, PHP_RAND_MAX);
- if (rnd_idx != cur_elem) {
- temp = elems[cur_elem];
- elems[cur_elem] = elems[rnd_idx];
+ RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
+ if (rnd_idx != n_left) {
+ temp = elems[n_left];
+ elems[n_left] = elems[rnd_idx];
elems[rnd_idx] = temp;
}
- cur_elem++;
}
HANDLE_BLOCK_INTERRUPTIONS();
Here is some PHP that will reproduce the problem. As you can see the
built-in shuffle() only generates 3 of the 6 possible combinations,
while the userland array_shuffle() correctly generates all 6 with equal
likelyhood.
<?php
function array_shuffle(&$array) {
$i = count($array);
while (--$i) {
$j = mt_rand(0, $i);
if ($i != $j) {
/* swap elements */
$tmp = $array[$j];
$array[$j] = $array[$i];
$array[$i] = $tmp;
}
}
}
function test($function) {
$a = array();
for ($i = 0; $i < 10000; $i++) {
$p = range(1,3);
$function($p);
$s = join('', $p);
$a[$s]++;
}
print "$function\n";
foreach($a as $k => $v) {
print "$k: $v\n";
}
}
test('shuffle');
test('array_shuffle');
?>
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/?id=18401&edit=1