summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChip Salzenberg <chip@perl.com>1997-02-20 07:04:03 +1200
committerChip Salzenberg <chip@atlantic.net>1997-02-22 02:41:53 +1200
commit93dc8474cb0353bd11e64192d213ed864602986f (patch)
tree5da5da58f19f1bc26e3c9e760237552b91a9b6e6
parent7efcc441c96951d44f6ea2c8a2be6ddcc6ea6d4c (diff)
downloadperl-93dc8474cb0353bd11e64192d213ed864602986f.tar.gz
Automatically call srand() before rand() if user didn't
-rw-r--r--pod/perlfunc.pod32
-rw-r--r--pp.c61
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`);
diff --git a/pp.c b/pp.c
index 7859606447..62a01ec5ae 100644
--- a/pp.c
+++ b/pp.c
@@ -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)