Numeric functions

srand#

Seed the pseudo-random number generator.

srand sets the internal state of the PRNG that rand draws from. Call it with an explicit integer to get a reproducible stream, or call it with no argument to reseed from the best entropy source the platform offers. Since Perl 5.14 srand returns the seed it used, so you can log it and replay the same run later.

Synopsis#

srand EXPR
srand

What you get back#

The seed that was installed, as an integer. For srand($n) the return value is $n (after the usual integer truncation). For argument-less srand() the return value is the auto-chosen seed drawn from system entropy — capture it if you ever want to reproduce the run.

my $seed = srand();                 # auto-seed, remember what we used
warn "seed for this run: $seed\n";

Before Perl 5.14 srand returned nothing useful. Code that relies on the seed return should declare the minimum version:

use v5.14;                          # so srand returns the seed

Global state#

srand mutates a single process-wide PRNG. Every subsequent call to rand in the same process — from any package, any module, any thread-free context — reads from that one state. There is no per-package or per-scope RNG. Consequences:

  • Calling srand($k) anywhere in the program affects every later rand call, including those inside modules you did not write.

  • Two processes that call srand($k) with the same $k produce identical rand streams. This is the basis of reproducible tests and the reason you must reseed after fork.

  • If srand is never called explicitly, it is called implicitly without argument the first time rand is invoked.

Examples#

Reproducible test case with an explicit seed — same input, same sequence, every run:

srand(42);
my @sample = map { rand() } 1..5;   # identical on every invocation

Seed from time() for rare-collision randomness across separate runs started at different wall-clock seconds. This is the classical pattern; it is not cryptographic-grade:

srand(time() ^ $$);                 # time XOR pid, old-school spread

Save-seed, restore-seed pattern for a test that picks a random subset of its cases but logs enough to replay any failure:

my $seed = srand();                 # auto-seed, capture it
eval { run_randomised_tests() };
if ($@) {
    warn "FAILED with seed=$seed — reproduce with: srand($seed)\n";
    die $@;
}

Reseed after fork so parent and child do not share a stream:

my $pid = fork();
die "fork: $!" unless defined $pid;
if ($pid == 0) {
    srand();                        # child gets fresh entropy
    exec_child_work();
}

Two independent streams from the same seed — useful when you want to checkpoint and resume, or diff two runs that diverged after a decision point:

srand(12345);
my @first  = map { rand() } 1..10;

srand(12345);
my @second = map { rand() } 1..10;  # identical to @first

Edge cases#

  • No-argument form auto-seeds with the best available entropy. On Linux this draws from /dev/urandom (or getrandom(2)). The seed is wide enough that you should treat it as opaque, not as a small integer.

  • Do not call srand() without arguments more than once per process. The PRNG’s internal state already carries more entropy than any single seed can restore, so re-seeding loses randomness rather than adding it. The two legitimate reasons to call it repeatedly are (a) with an explicit seed for reproducibility, and (b) once in each child after fork.

  • Decimal arguments are silently truncated to integer. srand(42) and srand(42.9) install the same seed. Always pass an integer so intent is obvious.

  • Same seed ⇒ identical rand stream. That is the whole point for tests; it is the whole problem for security.

  • Not cryptographically secure. rand/srand use a fast non-cryptographic PRNG. Do not use them to generate session tokens, nonces, keys, password salts, or anything an adversary must not be able to predict. Use Crypt::URandom or read from /dev/urandom directly.

  • PERL_RAND_SEED environment variable. If set to a non-negative integer at process startup, argument-less srand() (including the implicit call triggered by the first rand) installs a deterministic seed derived from that value. The derivation is deliberately unspecified; only same-value-same-binary-same-code reproducibility is guaranteed. Intended for debugging and performance analysis. The variable is read once at startup; mutating %ENV later has no effect on the current process.

  • Threads (use threads): each interpreter clone gets its own PRNG state. Seeding in one thread does not affect another.

  • Scope of the seed: there is no way to local-ise the PRNG state. If a library you call in between does an srand, your stream is perturbed. Capture and restore manually if that matters.

Differences from upstream#

Fully compatible with upstream Perl 5.42. PERL_RAND_SEED is honoured with the same “deliberately unspecified but reproducible” contract as perl5.

See also#

  • rand — the consumer of the state srand installs; draws the next value from the seeded stream

  • time — seconds since the epoch; the classic quick-and-dirty seed source for non-security code (srand(time() ^ $$))

  • Crypt::URandom — cryptographically secure random bytes from the OS entropy pool; use this, not rand, for tokens and keys

  • Math::Random::MT — Mersenne Twister PRNG with its own independent state, when you need a second stream that is not perturbed by library calls to rand

  • perlrun — documents the PERL_RAND_SEED environment variable and other startup knobs