【问题标题】:How to generate a good seed如何产生好种子
【发布时间】:2019-08-20 12:09:36
【问题描述】:

我正在寻找一种方法来生成一个好的种子,以便在同时开始的进程中生成不同系列的随机数。 我想避免使用数学或加密库之一,因为我非常频繁地选择随机数并且我的 cpu 资源非常有限。

我找到了几个设置种子的例子。我使用以下方法对其进行了测试:

  1. 从 5000 个选项中选择 100 个随机数的短程序。所以每个值都有 2% 的机会被选中。
  2. 运行这个程序 100 次,所以理论上,在一个真正随机的环境中,所有可能的值都应该至少选择一次。
  3. 计算根本未选择的值的数量。

这是我使用的 perl 代码。在每个测试中,我只选择一种生成种子的方法:

#!/usr/bin/perl
#$seed=5432;
#$seed=(time ^ $$);
#$seed=($$ ^ unpack "%L*", `ps axww | gzip -f`);
$seed=(time ^ $$ ^ unpack "%L*", `ps axww | gzip -f`);

srand ($seed);

for ($i=0 ; $i< 100; $i++) {
        printf ("%03d \n", rand (5000)+1000);
}

我运行程序 100 次并计算未选择的值:

# run the program 100 times
for i in `seq 0 99`; do /tmp/rand_test.pl ; done  > /tmp/list.txt
# test 1000 values (out of 5000). It should be good-enough representation.
for i in `seq 1000 1999`; do echo -n "$i  "; grep -c $i /tmp/list.txt; done   | grep " 0" | wc -l

表格显示了测试的结果(值越小越好):

count      Seed generation method
114    default - the line: "srand ($seed);" is commented ou
986    constant seed (5432)
122    time ^ $$
125    $$ ^ unpack "%L*", `ps axww | gzip -f`
163    time ^ $$ ^ unpack "%L*", `ps axww | gzip -f`

恒定种子方法显示未选择 986 或 1000 个值。换言之,仅选择了 1.4% 的可能值。这足以接近预期的 2%。

但是,我预计在少数地方推荐的最后一个选项会明显优于默认选项。

有没有更好的方法为每个进程生成种子?

【问题讨论】:

  • 您的应用程序中是否需要可重复的“随机性”?您将生成的随机数将如何使用?
  • 没有。为了获得可重复的“随机性”,我可以简单地使用相同的种子。
  • 您能否回答我的另一个问题:您生成的随机数将如何使用?如果这些数字会以任何方式提高信息安全性(例如,它们用作随机密码、随机数或加密密钥),那么您应该简单地使用加密 RNG(例如 Perl 中的Crypt::URandom)并生成 随机数字 用它而不是 seeds
  • 使用随机数我将组成一个“用户名”:$user_name_to_fetch = sprintf("name%015d", rand($max_user_id)); 从数据库中查询。我想通过在多个客户端进程中运行查询,在最短的时间内覆盖大多数数据库。如何使用Crypt::URandom 生成随机数?它生成随机字符串。
  • 地穴::随机::种子。试一试,并使用 TESHA2-strong 方法对其性能进行基准测试/分析。如果您只在需要种子时调用它,它可能会非常快。播种 RNG 后,在可预见的未来您不必再次播种。

标签: perl random random-seed


【解决方案1】:

不要生成种子。让 Perl 为你做这件事。不要调用srand(如果你这样做的话,也不要在没有参数的情况下调用它)。

引用srand

如果 srand 没有被显式调用,它会在第一次使用 rand 运算符时被隐式调用而没有参数

当使用参数调用时,srand 将其用作种子;否则它(半)随机选择一个种子。

它不只是将时间用作种子。

$ perl -M5.014 -E'say for srand, srand'
2665271449
1007037147

【讨论】:

    【解决方案2】:

    我非常频繁地选择随机数,我的 cpu 资源非常有限。

    您甚至在进行测量之前就担心了。

    有没有更好的方法为每个进程生成种子?

    Yes.你必须离开容易被操纵的用户空间。只需使用Crypt::URandom

    • 对于任何目的都是安全的,包括获取种子。
    • 它将为每个操作系统 (see source code) 使用内核 CSPRNG,从而避免上述文章中显示的问题。
    • 它不受documented rand weakness的影响。

    【讨论】:

    • tnx.非常有趣的参考。当我在documented rand weakness 中测试代码时,它返回了 1000000。当我将映射更改为:my %r = map { int(rand(1_000_000)) =&gt; undef } 1 .. 1_000_000; 时,它开始返回大约 632K 的值。
    • 我看了Crypt::URandom。如何将 N 字节长字符串转换为 00 .. X 范围内的整数?
    • 将字节视为 N 位的 256 位自然数。除以 256**N(最大 val)得到 0..1 之间的有理数。乘以 X 得到 0..X 之间的有理数。 use bignum qw(hex); use Crypt::URandom qw(urandom); my $N = 10; my $X = 10_000; my $bigint = hex unpack 'H*', urandom $N; my $smallrat = $bigint / 256**$N; print $smallrat * $X;
    • @Yuval “rand 弱点”仅适用于 microsoft windows(实际上,并非如此,但其他内置 rand 实现的弱点要少得多)
    【解决方案3】:

    您的目标似乎是如何生成随机数,而不是如何生成种子。在大多数情况下,只需使用加密 RNG(例如 Perl 中的 Crypt::URandom)来生成您想要的随机数,而不是为另一个 RNG 生成种子。 (通常,加密 RNG 会为您处理播种和其他问题。)您不应使用较弱的 RNG,除非——

    • 您生成的随机值不涉及信息安全(例如,随机值既不是密码,也不是随机数,也不是加密密钥),并且
    • 要么——
      • 您关心可重复的“随机性”(这里不是这种情况),或者
      • 您已测量应用程序的性能并发现随机数生成是性能瓶颈。

    由于您将生成随机名称以查询可能位于远程位置的数据库,因此随机数生成本身不太可能成为性能瓶颈。

    【讨论】:

      猜你喜欢
      • 2020-10-14
      • 1970-01-01
      • 2020-12-15
      • 1970-01-01
      • 2019-08-10
      • 2013-01-25
      • 2023-03-24
      • 2021-10-04
      • 1970-01-01
      相关资源
      最近更新 更多