|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2002-07-18 01:03 UTC] adam at trachtenberg dot 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');
?>
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Thu Nov 06 06:00:02 2025 UTC |
- 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; Thanks for detailed report. This diff clearly show where to fix. Swapping values requires 3 lines!!