diff options
-rw-r--r-- | pod/perlfunc.pod | 32 | ||||
-rw-r--r-- | pp.c | 61 |
2 files changed, 56 insertions, 37 deletions
diff --git a/pod/perlfunc.pod b/pod/perlfunc.pod index 9d21587696..b3cf4e4205 100644 --- a/pod/perlfunc.pod +++ b/pod/perlfunc.pod @@ -2275,8 +2275,8 @@ If EXPR is omitted, uses $_. Returns a random fractional number between 0 and the value of EXPR. (EXPR should be positive.) If EXPR is omitted, returns a value between -0 and 1. This function produces repeatable sequences unless srand() -is invoked. See also srand(). +0 and 1. Automatically calls srand() unless srand() has already been +called. See also srand(). (Note: if your rand function consistently returns numbers that are too large or too small, then your version of Perl was probably compiled @@ -3036,17 +3036,23 @@ root of $_. =item srand EXPR -Sets the random number seed for the C<rand> operator. If EXPR is omitted, -uses a semi-random value based on the current time and process ID, among -other things. In versions of Perl prior to 5.004 the default seed was -just the current time(). This isn't a particularly good seed, so many -old programs supply their own seed value (often C<time ^ $$> or C<time ^ -($$ + ($$ << 15))>), but that isn't necessary any more. - -You need something much more random than the default seed for -cryptographic purposes, though. Checksumming the compressed output of -one or more rapidly changing operating system status programs is the -usual method. For example: +=item srand + +Sets the random number seed for the C<rand> operator. If EXPR is +omitted, uses a semi-random value based on the current time and process +ID, among other things. In versions of Perl prior to 5.004 the default +seed was just the current time(). This isn't a particularly good seed, +so many old programs supply their own seed value (often C<time ^ $$> or +C<time ^ ($$ + ($$ << 15))>), but that isn't necessary any more. + +In fact, it's usually not necessary to call srand() at all, because if +it is not called explicitly, it is called implicitly at the first use of +the C<rand> operator. + +However, you need something much more random than the default seed for +cryptographic purposes. Checksumming the compressed output of one or +more rapidly changing operating system status programs is the usual +method. For example: srand (time ^ $$ ^ unpack "%L*", `ps axww | gzip`); @@ -29,8 +29,11 @@ typedef int IBW; typedef unsigned UBW; -static SV* refto _((SV* sv)); static void doencodes _((SV* sv, char* s, I32 len)); +static SV* refto _((SV* sv)); +static U32 seed _((void)); + +static bool srand_called = FALSE; /* variations on pp_null */ @@ -1296,6 +1299,10 @@ PP(pp_rand) value = POPn; if (value == 0.0) value = 1.0; + if (!srand_called) { + (void)srand((unsigned)seed()); + srand_called = TRUE; + } #if RANDBITS == 31 value = rand() * value / 2147483648.0; #else @@ -1316,38 +1323,44 @@ PP(pp_rand) PP(pp_srand) { dSP; - I32 anum; + UV anum; + if (MAXARG < 1) + anum = seed(); + else + anum = POPu; + (void)srand((unsigned)anum); + srand_called = TRUE; + EXTEND(SP, 1); + RETPUSHYES; +} - if (MAXARG < 1) { +static U32 +seed() +{ + U32 u; #ifdef VMS # include <starlet.h> - unsigned int when[2]; - _ckvmssts(sys$gettim(when)); - anum = when[0] ^ when[1]; + unsigned int when[2]; + _ckvmssts(sys$gettim(when)); + u = when[0] ^ when[1]; #else # ifdef HAS_GETTIMEOFDAY - struct timeval when; - gettimeofday(&when,(struct timezone *) 0); - anum = when.tv_sec ^ when.tv_usec; + struct timeval when; + gettimeofday(&when,(struct timezone *) 0); + u = when.tv_sec ^ when.tv_usec; # else - Time_t when; - (void)time(&when); - anum = when; + Time_t when; + (void)time(&when); + u = when; # endif #endif -#if !defined(PLAN9) /* XXX Plan9 assembler chokes on this; fix coming soon */ - /* 17-Jul-1996 bailey@genetics.upenn.edu */ - /* What is a good hashing algorithm here? */ - anum ^= ( ( 269 * (U32)getpid()) - ^ (26107 * (U32)&when) - ^ (73819 * (U32)stack_sp)); +#ifndef PLAN9 /* XXX Plan9 assembler chokes on this; fix needed */ + /* What is a good hashing algorithm here? */ + u ^= ( ( 269 * (U32)getpid()) + ^ (26107 * (U32)&when) + ^ (73819 * (U32)stack_sp)); #endif - } - else - anum = POPi; - (void)srand(anum); - EXTEND(SP, 1); - RETPUSHYES; + return u; } PP(pp_exp) |