【发布时间】:2015-07-05 06:22:17
【问题描述】:
我需要生成 16 个字符的长字符串(来自 SHA1 哈希),其中仅包含 0 和 1,概率为 50%(统计上大多数情况下字符串中 1 的数量与 0 的数量相同)。
所以我编写了基准测试,并尝试将每个 $hash 字符转换为二进制。 结果很糟糕,我的意思是,如果我将前导零添加到二进制转换的哈希中,正确的概率远非正确。 当我没有在二进制转换中添加前导零时,概率接近正确:
Percentage all 0 or all 1: 0.0012%
Percentage all 0 or all 1 except 1 character : 0.0146%
Percentage all 0 or all 1 except 2 characters: 0.0812%
但是下面的代码应该产生的真正正确概率仍然是:
Percentage all 0 or all 1: 0.003%
Percentage all 0 or all 1 except 1 character : 0.048%
Percentage all 0 or all 1 except 2 characters: 0.376%
我怎么知道它的正确概率?我将二进制转换更改为简单的 mt_rand(0,1) 十六次(以及其他确认测试)。
它必须从 sha1 哈希生成,才能由该哈希确定。 任何人都有想法,如何修复我的代码以产生正确的概率结果?我已经连续尝试了 10 个小时。
function binary($text){
$list = '';
$temp = '';
$i = 0;
while ($i < 16){
if (is_numeric($text[$i])){
$list .= decbin( $text[$i] );//sprintf( "%08d", decbin( $text[$i] ));
} else {
$temp = ord($text[$i]);
$list .= decbin( $temp );
// $list .= sprintf( "%08d", decbin( $temp ));// substr("00000000",0,8 - strlen($temp)) . $temp;
}
$i++;
}
return $list;
}
$y = 0;
$trafien = 0;
$trafien1= 0;
$trafien2= 0;
$max = 500000;
while ($y < $max){
$time = uniqid() . mt_rand(1,999999999999);
$seed = 'eqm2890rmn9ou8nr9q2';
$hash = sha1($time . $seed);
$last4 = substr($hash, 0, 40);
$binary = binary($last4);
$final = substr($binary, 0,16);
$ile = substr_count($final, '0');
$ile2= substr_count($final, '1');
if ($ile == 16 || $ile2 == 16){
echo "\n".$last4 ." " . 'binary: '. $binary .' final: '. $final;
$trafien += 1;
}
if ($ile == 15 || $ile2 == 15){
$trafien1 += 1;
}
if ($ile == 14 || $ile2 == 14){
$trafien2 += 1;
}
$y++;
}
$procent = ($trafien * 100) / $max;
$procent1= ($trafien1 * 100) / $max;
$procent2= ($trafien2 * 100) / $max;
echo "\nPercentage all 0 or all 1: ". $procent . "%";
echo "\nPercentage all 0 or all 1 except 1 character : ". $procent1 . "%";
echo "\nPercentage all 0 or all 1 except 2 characters: ". $procent2 . "%";
【问题讨论】:
-
使用 uniqid() 可能不适合随机数生成器,因为它基于微时间。
-
@Devon uniqid() 仅用于基准测试,实际代码哈希以不同的方式生成
-
为什么您在基准测试中生成的哈希值不同?
-
因为在这里获取哈希的方式并不重要,它在基准测试中应该是唯一的,并且我在基准测试中没有例如 user_id,所以我使用 mt_rand + uniqid()