Successfully reported this slideshow.
Upcoming SlideShare
×

• Full Name
Comment goes here.

Are you sure you want to Yes No

1. 1. PHP と 乱打舞図 2014/03/15 第5回 闇PHP勉強会 do_aki
2. 2. ＠do_aki http://do-aki.net/
3. 3. title was born from typo らんだまいず 乱打舞図 モテカルロ法っぽくない？
4. 4. randomize • 無秩序に並び替えること • 規則性がないこと • 偏りがないこと
6. 6. randomize function in php shuffle str_shuffle
7. 7. give it try (php 5.5.10) function bench(\$name, \$suffle_func) { \$result = []; for (\$i=0; \$i<60000;++\$i) { \$a = range(1, 3); \$suffle_func(\$a); \$r = implode('', \$a); \$result[\$r]=isset(\$result[\$r])? \$result[\$r]+1 : 1; } print "{\$name}¥n"; ksort(\$result); print_r(\$result); }
8. 8. shuffle / str_shuffle bench("shuffle", "shuffle"); bench("str_shuffle", function(&\$ary) { \$str = str_shuffle(implode('', \$ary)); \$ary = str_split(\$str, 1); });
9. 9. result of shuffle shuffle Array ( [123] => 9873 [132] => 10104 [213] => 9999 [231] => 9944 [312] => 9998 [321] => 10082 )
10. 10. result of str_shuffle str_shuffle Array ( [123] => 9956 [132] => 9928 [213] => 10080 [231] => 9969 [312] => 10149 [321] => 9918 )
11. 11. No Problem (in current version of php)
12. 12. 過去の shuffle は等分散ではなかった
13. 13. implementation of shuffle(current version) long n_elems, rnd_idx, n_left; char temp; /* The implementation is stolen from array_data_shuffle */ /* Thus the characteristics of the randomization are the same */ n_elems = len; if (n_elems <= 1) { return; } n_left = n_elems; while (--n_left) { rnd_idx = php_rand(TSRMLS_C); RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX); if (rnd_idx != n_left) { temp = str[n_left]; str[n_left] = str[rnd_idx]; str[rnd_idx] = temp; } } ext/standard/string.c より抜粋 / shuffle の実装も同じ
14. 14. implementation of shuffle (php < 4.3.0) PHP_FUNCTION(shuffle){ zval *array; if (zend_parse_parameters(1 TSRMLS_CC, "a", &array) == FAILURE){ RETURN_FALSE; } if (zend_hash_sort(Z_ARRVAL_PP(&array), (sort_func_t)php_mergesort, array_data_shuffle, 1 TSRMLS_CC) == FAILURE) { RETURN_FALSE; } RETURN_TRUE; } } static int array_data_shuffle(const void *a, const void *b TSRMLS_DC) { return (php_rand(TSRMLS_C) % 2) ? 1 : -1; }
15. 15. ＿人人人人人人人人人人人人＿ ＞ ランダムマージソート ＜ ￣Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y￣
16. 16. implementation of str_shuffle (php < 4.3.0) PHP_FUNCTION(str_shuffle) { /* Note : by using current php_string_shuffle for string */ /* with 6 chars (6! permutations) about 2/3 of them are */ /* computed for 6! calls for the function. So it isn't so */ /* unique. The ratio is the same for other lengths. */ char *str; int i, str_len; i = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { RETURN_FALSE; } zend_qsort((void *)str, str_len, sizeof(char), php_string_shuffle TSRMLS_CC); RETURN_STRINGL(str, str_len, 1); }
17. 17. implementation of str_shuffle (php < 4.3.0) static int php_string_shuffle(const void *a, const void *b TSRMLS_DC) { long rnd; rnd = php_rand(TSRMLS_C); if (rnd % 3) return 1; else if (rnd % 5) return 0; else return -1; }
18. 18. ＿人人人人人人人人人人人人人人人＿ ＞ ランダム(?) クイックソート ＜ ￣Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y￣
19. 19. emulate old shuffle (php) bench("old_shuffle", function(&\$ary){ usort(\$ary, function(\$a, \$b) { return (rand() % 2) ? 1 : -1; }); }); bench("old_str_shuffle", function(&\$ary){ usort(\$ary, function(\$a, \$b) { \$rnd = rand(); if (\$rnd % 3) { return 1; } elseif (\$rnd % 5) { return 0; } else { return -1; } }); });
20. 20. result old_shuffle Array ( [123] => 22358 [132] => 7627 [213] => 3771 [231] => 3827 [312] => 7487 [321] => 14930 ) old_str_shuffle Array ( [123] => 30982 [132] => 4453 [213] => 5994 [231] => 2928 [312] => 8979 [321] => 6664 )
21. 21. 現在の shuffle は、本当に問題ないのか？
22. 22. php_rand(C) := rand (php)
23. 23. random in php rand mt_rand
24. 24. rand vs mt_rand • rand – libc の random or lrand48 or rand – environment dependent • mt_rand – Mersenne Twister (MT19937) – implementation dependent
25. 25. re-imprement of shuffle (environment independent) function mt_shuffle(&\$ary) { \$n = count(\$ary); while(--\$n) { \$rnd_idx = mt_rand(0, \$n); if (\$rnd_idx != \$n) { \$tmp = \$ary[\$n]; \$ary[\$n] = \$ary[\$rnd_idx]; \$ary[\$rnd_idx] = \$tmp; } } }
26. 26. Conclusion • 現在の shuffle / str_shuffle は、均等に分配 される • 異なる環境での再現性が必要なら mt_rand つかって再実装しよう • php 4 はオワコン
27. 27. End Of Slide Let’s enjoy PHP hack life ;-)