Php radomize

28
PHP 乱打舞図 2014/03/15 5PHP勉強会 do_aki

description

第5回 闇php勉強会

Transcript of Php radomize

Page 1: Php radomize

PHP と

乱打舞図 2014/03/15

第5回 闇PHP勉強会

do_aki

Page 2: Php radomize

@do_aki

http://do-aki.net/

Page 3: Php radomize

title was born from typo

らんだまいず

乱打舞図 モテカルロ法っぽくない?

Page 4: Php radomize

randomize

• 無秩序に並び替えること

• 規則性がないこと

• 偏りがないこと

Page 6: Php radomize
Page 7: Php radomize

randomize function in php

shuffle

str_shuffle

Page 8: Php radomize

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); }

Page 9: Php radomize

shuffle / str_shuffle

bench("shuffle", "shuffle");

bench("str_shuffle", function(&$ary) {

$str = str_shuffle(implode('', $ary));

$ary = str_split($str, 1);

});

Page 10: Php radomize

result of shuffle

shuffle

Array

(

[123] => 9873

[132] => 10104

[213] => 9999

[231] => 9944

[312] => 9998

[321] => 10082

)

Page 11: Php radomize

result of str_shuffle

str_shuffle

Array

(

[123] => 9956

[132] => 9928

[213] => 10080

[231] => 9969

[312] => 10149

[321] => 9918

)

Page 12: Php radomize

No Problem

(in current version of php)

Page 13: Php radomize

過去の shuffle は等分散ではなかった

Page 14: Php radomize

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 の実装も同じ

Page 15: Php radomize

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;

}

Page 16: Php radomize

_人人人人人人人人人人人人_ > ランダムマージソート <  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄

Page 17: Php radomize

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); }

Page 18: Php radomize

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; }

Page 19: Php radomize

_人人人人人人人人人人人人人人人_ > ランダム(?) クイックソート <  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄

Page 20: Php radomize

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; } }); });

Page 21: Php radomize

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 )

Page 22: Php radomize

現在の shuffle は、本当に問題ないのか?

Page 23: Php radomize

php_rand(C) := rand (php)

Page 24: Php radomize

random in php

rand

mt_rand

Page 25: Php radomize

rand vs mt_rand

• rand – libc の random or lrand48 or rand

– environment dependent

• mt_rand

– Mersenne Twister (MT19937)

– implementation dependent

Page 26: Php radomize

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; } } }

Page 27: Php radomize

Conclusion

• 現在の shuffle / str_shuffle は、均等に分配される

• 異なる環境での再現性が必要なら mt_rand つかって再実装しよう

• php 4 はオワコン

Page 28: Php radomize

End Of Slide

Let’s enjoy PHP hack life ;-)