【问题标题】:Generate 0 and 1, pseudorandom, 16 char long string生成 0 和 1,伪随机,16 字符长的字符串
【发布时间】: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()

标签: php random binary sha1


【解决方案1】:

当您只使用 4 个字符并转换为二进制时,我想我不明白为什么需要在这里重新发明轮子或使用 sha1()。这似乎工作正常:

$n = null;
for ($i=1; $i<=16; $i++) {
  $n .= mt_rand(0,1);
}

这是我编写的基准脚本:

// $app for number of appearances
$app[0] = 0;
$app[1] = 0;
$sample = 10000;

for ($t=1; $t<=$sample; $t++) {

  $n = null;
  for ($i=1; $i<=16; $i++) {
    $n .= mt_rand(0,1);
  }

  $app[0] += substr_count($n, 0);
  $app[1] += substr_count($n, 1);
}

print_r($app);
echo "Probability of 0: ".($app[0] / ($sample * 16))."\n";
echo "Probability of 1: ".($app[1] / ($sample * 16))."\n";

10000 样本大小的输出:

Array
(
    [0] => 80079
    [1] => 79921
)
Probability of 0: 0.50049375
Probability of 1: 0.49950625

100000 样本大小的输出:

Array
(
    [0] => 799390
    [1] => 800610
)
Probability of 0: 0.49961875
Probability of 1: 0.50038125

【讨论】:

  • 我在我的帖子中写过关于使用 mt_rand(0,1),您没有阅读我的帖子 :P,还说过两次我必须通过哈希来执行此操作。它必须由哈希确定。相信我,如果可以的话,我会这样做:/
  • 我知道你这么说,但你没有解释原因。解释为什么需要通过哈希确定它可能更有意义。
  • 因为我必须有证据证明我没有编造这些数字(0/1),它们是由独立的确定性哈希创建的。任何人都可以验证这个数字是否真的是由这个哈希创建的。
  • 这段代码的最终目的是什么?我看不到使用 sha1 哈希的最后 4 个字符如何添加任何类型的验证。他们如何验证原始哈希?您无法从最后 16 位重建它,即使您可以为什么这与来自 mt_rand 的随机 16 位不同?这是家庭作业还是什么?否则我不明白这一点。
  • 不,这不是家庭作业。用户不需要重建散列,他知道这个散列是如何创建的(在实时代码中,创建散列没有随机性)。所以他可以创建整个哈希并使用已知的算法(上面的这个我还不能正常工作)来验证这 16 个字符长的 0/1 :)
【解决方案2】:

好的,我解决了,由于缺乏知识,我过度劳累。您可以使用 sha1 函数 sha1(data, true) 的直接原始二进制输出。那么你就有了真正的确定性 0/1 随机性 :)

【讨论】:

    猜你喜欢
    • 2014-11-22
    • 2010-09-08
    • 1970-01-01
    • 2018-01-25
    • 2013-10-10
    • 2021-11-10
    • 1970-01-01
    • 2023-04-06
    • 2017-08-01
    相关资源
    最近更新 更多