0

次のコードを見てください。

srand(localtime);

for (my $ik = 0; $ik < 3; $ik += 1)
{
    print int(rand(10)),"\n";
    sleep(1);
}

上記のコードを十分な時間(5〜10秒)間隔で複数回呼び出しますが、出力シーケンスは同じです。

すべての呼び出しにシードを設定したのでlocaltime、異なるシードを使用する必要があり、時間のギャップのために、おそらく異なる 3 つの数字のシーケンスを生成する必要があります。何度も同じシーケンスを取得するのはなぜですか。

注: コードはループ内ではなく、複数回実行される Perl ファイル内にあります。

ドキュメントによると、複数のインスタンスが同じ「秒」で実行されて同じシードにつながると、このシードは失敗しますが、ここではそうではありません。

編集:: @simbabqueによる解決策は役立ちますが、期待されるランダム性は得られません。以下の前述のソリューションに関する私のコメントを見てください。

4

2 に答える 2

7

use strictこれをと で実行してみてくださいuse warnings。それはあなたに与えるでしょう:

Argument "Thu Jun 21 13:04:41 2012" isn't numeric in srand at ...

そして、あなたの問題があります。localtimeスカラー コンテキストで文字列を返します。代わりに使用してみてくださいtime。これは、UNIX タイムスタンプを整数として返します。srand機能するには数値が必要です。

それにData::Dumperを追加すると、コードのシードが常に であることがわかります1

no strict; no warnings;
use Data::Dumper;
print Dumper srand(localtime);

for (my $ik = 0; $ik < 3; $ik += 1)
{
    print int(rand(10)),"\n";
    sleep(1);
}

言います:

$VAR1 = 1;
0
2
6

必要なものは次のとおりです。

use strict; use warnings;
srand(time);
for (my $ik = 0; $ik < 3; $ik += 1)
{
    print int(rand(10)),"\n";
    sleep(1);
}

編集:

良いランダム性が必要な場合、これはまだあまり良い考えではありません。ドキュメントは次のように述べています。

5.004 より前のバージョンの Perl では、デフォルトのシードはちょうど現在の時刻でした。これは特に良いシードではないため、多くの古いプログラムは独自のシード値 (多くの場合time ^ $$またはtime ^ ($$ + ($$ << 15))) を提供しますが、それはもはや必要ありません。

srand実際に再現可能な結果が必要な場合 (つまり、テスト用) でない限り、呼び出しをまったく省略することをお勧めします。

于 2012-06-21T11:05:35.700 に答える
0

一般に、 PRNGを繰り返しシードすることでより良いランダム性を期待する理由はありません。

次のスクリプトを使用して、元の質問で何が起こっているかを確認できます。

#!/usr/bin/env perl

use strict; use warnings;
use 5.014;

for (1 .. 3) {
    my $seq = newseq(3, 5);
    printf "Seed = %s\n", $seq->{seed};
    my $it = $seq->{generator};
    while (defined(my $r = $it->())) {
        print "$r\n";
    }
    sleep 5;
}


sub newseq {
    my ($length, $limit) = @_;
    $length //= 10;
    $limit  //= 10;

    my $seed = srand(time);
    return {
        seed => $seed,
        generator => sub {
            return unless $length-- > 0;
            return rand($limit);
        },
    };
}

ただし、統計的に独立したジェネレーターが必要な場合は、Math::Random::MT::Autoを使用して個々の PRNG オブジェクトを作成できます。

#!/usr/bin/env perl

use strict; use warnings;
use 5.014;

use strict;
use warnings;
use Math::Random::MT::Auto qw(:!auto);

my $prng1 = Math::Random::MT::Auto->new(SOURCE => '/dev/random');
my $prng2 = Math::Random::MT::Auto->new(SOURCE => 'random_org');

say $prng1->rand();
say $prng2->irand();
于 2012-06-21T13:39:58.020 に答える