srand

(PHP 3, PHP 4, PHP 5)

srand -- 播下随机数发生器种子

说明

void srand ( [int seed] )

seed 播下随机数发生器种子。从 PHP 4.2.0 版开始,seed 参数变为可选项,当该项为空时,会被设为随时数。

例子 1. srand() 范例

<?php
// seed with microseconds
function make_seed()
{
    list(
$usec, $sec) = explode(' ', microtime());
    return (float)
$sec + ((float) $usec * 100000);
}
srand(make_seed());
$randval = rand();
?>

注: 自 PHP 4.2.0 起,不再需要用 srand()mt_srand() 函数给随机数发生器播种,现已自动完成。

参见 rand()getrandmax()mt_srand()


add a note add a note User Contributed Notes
bootc at bootc dot net
06-Jun-2005 11:03
OK, to summarize what people have been saying so far:

1. DO NOT seed the RNG more than once if you can help it!
2. You HAVE TO seed the RNG yourself if you are using PHP < 4.2.0.
3. Using a prime multiplier to microtime() probably does very little. Use the Mersenne Twister instead.
4. You can use the Mersenne Twister PRNG with the mt_rand and mt_srand functions. This is faster and is more random.
greenmonkey (at) gmx dot net
07-Feb-2005 05:40
if u r looking for a good PRNG try google with "Mersenne Twister"
corey at eyewantmedia dot com
07-Jan-2005 12:22
Hey, I use rand() all the time to get a rough probability of something happening. I went ahead and wrote a little function to help with the situation "I wish this thing would happen 2% of the time, so here is 5 lines of code to figure it out" since I run into it so much. Obviously, this is pretty similar to the if rand($x, $y) <$soething way, but I find it a little more flexible.

/**
 * @return boolean
 * @param int $baseChance
 * @param int $chanceAmplifier
 * @desc Returns a true or false value based on a whether a random number
 *        in the range 1 - (100 * $chanceAmplifier) is less than $baseChance.
*/
function RandomChance($baseChance, $chanceAmplifier = 1) {
   srand( ((int)((double)microtime()*1000003)) ); // get a good seed
   $totalBag = 100 * $chanceAmplifier; // set up max limit
  
   $probCheck = rand(1,$totalBag); // get random number
  
   if ( ($probCheck < $baseChance) ) { //compare it to $baseChance
       $result = true;
   }  else {
       $result = false;
   }

   return $result; //Yay!
}
davidaylmer zebra gmail.com (zebra = at)
03-Jan-2005 10:42
Just for the convienience of others...
1000003 is a prime number

So (double)microtime()*1000003 may work better for some applications.
edublancoa at gmail dot com
23-Dec-2004 05:39
Another use of srand is to obtain the same value of rand in a determined time interval. Example: you have an array of 100 elements and you need to obtain a random item every day but not to change in the 24h period (just imagine "Today's Photo" or similar).
<?php
$seed
= floor(time()/86400);
srand($seed);
$item = $examplearray[rand(0,99)];
?>
You obtain the same value every time you load the page all the 24h period.
no at spam dot com
02-Sep-2004 07:59
I simply use this, and it has always worked fine:

function initRand ()
{
   static $randCalled = FALSE;
   if (!$randCalled)
   {
       srand((double) microtime() * 1000000);
       $randCalled = TRUE;
   }
}
function randNum ($low, $high)
{
   initRand();
   $rNum = rand($low, $high);
   return $rNum;
}
Codaholics dot com
17-Jun-2004 01:59
office's comment about multiplying by 1234567 instead of 1000000 is slightly misguided for a couple of reasons.

first, as the editor note would indicate, 1234567 is not a prime number.

second, the problem he is attempting to fix is that the random values are slowly converging. this, however, is not a problem with the seeding of the random number generator, but a problem with the RNG itself.  most default RNGs that come with programming languages will converge because they were written for efficiency and to function in everyday programs.

if you need a Pseudo Random Number Generator (PRNG) that is cryptographically secure and does not converge after repeated use without seeding... you will unfortunately have to use a different generator.  There are several out there such as the MersenneTwister, Yarrow (by Bruce Schneierer of Counterpane Security) and more being made every day.  Due to the hassle of finding a reputable PRNG, it is recommended that you only need to use those for issues that require strong security such as gambling games and cryptography.

hope this cleared things up :)
vinod at todays-deals dot com
20-Oct-2002 04:57
hi,
Here is one useful function that returns random string for given length

//#########################//

function randomstring($len)
{
   srand(date("s"));
   while($i<$len)
     {
       $str.=chr((rand()%26)+97);
       $i++;
   }
 
   $str=$str.substr(uniqid (""),0,22);
   return $str;
}

$rand_value=randomstring(10);

//#########################//

Thanks
Vinod

http://www.todays-deals.com
office at at universalmetropolis dot com
27-Apr-2002 05:40
[Editor's note: 1234567 is NOT a prime number]

I created an application that requires millions of different random values replicating dice and have found over substantial time, the numbers even up towards the middle.

May I suggest rather than this:

(double)microtime()*1000000

Use this instead:

(double)microtime()*1234567

1000000 is an even number, divisible by almost anything. 1234567 is a prime number and is hence uneven so it gives a little more flexibility with range.

Don't know if this change was the main reason for affecting the application, but it seemed to help.
ceo at l-i-e dot com
23-Feb-2002 09:53
In addition to my earlier post being stupidly coded with $wasseeded = TRUE :-| here is an update:

In PHP4, I *BELIEVE* the random number generator will seed itself if you don't seed it.

In PHP3, or some versions of PHP3?, that was not the case -- An unseeded rand() wouldn't be random.

While it would "work fine" in terms of spitting out a number, an unseeded random number generator won't be very random in many situations unless it has been properly seeded.

I'm afraid I can't explain all the details of why this is because A) it would be an entire textbook, and B) I don't know them all by heart, even if I understood them 20 years ago in college.

If you are running PHP4, you are probably okay, and if you are happy with the randomness of your values, you are fine, but you may want to do a little test like:

<?php
  $stats
[1] = 0;
 
$stats[2] = 0;
 
$stats[3] = 0;
  for (
$i = 0; $i < 1000; $i++){
  
$choice = rand(1,3);
   if (!
$i){
     echo
"First random choice: $choice<BR>\n";
   }
  
$stats[$choice]++;
  }
 
reset($stats);
  while (list(
$num, $count) = each($stats)){
   echo
"$num: $count<BR>\n";
  }
?>

Run the test a half-dozen times and check that the distribution of 1, 2, and 3 is even, and that the first number chosen is not the same every time.

This is hardly an exhaustive test, but it at least gives some reassurance that the numbers aren't completely predictable.

You may also wish to switch to http://php.net/mt_rand which is faster (if you generate a *LOT* of numbers) and allegedly a "better" (more random) function.

Again, it would be an entire book to explain why mt_rand is "more random"...

YMMV.  If you're doing "Casino Slots" with real money, you'd better do your homework on this.  If you're giving away a free CD or something silly, who cares?
sinister at cyberfrag dot com
22-Jan-2002 03:08
It's pretty easy how he's getting a highly random number. Microtime measures the time since the Epoch (0:00:00 January 1, 1970 GMT). Microtime() returns a string of 2 parts, the current microsecond count, a space, and then the time since the Epoch. By using (double), he chops off the seconds-since-Epoch time, and uses the "current microsecond count" until the next second.

Since time moves constantly, microseconds is the smallest unit a programming language makes use of, the current microseconds up until the next second will give you a million different numbers, every second. Now simply multiply the 0.xxxxxx number by 1,000,000 (like back in Jr. High School), and it will niftily place the 0.xxxxxx number in xxxxxx fashion for your seed.
mlwmohawk at mohawksoft dot com
02-Nov-2001 11:51
srand() is pretty tricky to get right. You should never seed a random number generator more than once per php process, if you do, your randomness is limited to the source of your seed.

The microtime function's micro-seconds portion has a very finite resolution, that is why the make_seed function was added to the document. You should never get the same seed twice.

In the later CVS versions, PHP will seed the random generator prior to performing a rand() if srand() was not previously called.
trobinson-a-t-gksystems-d-o-t-com
02-Nov-2001 06:26
The need to seed.
You might run a script like this:
   echo mt_rand(0,99999999);
a bunch of times, say by pressing Refresh in the browser, and get a different result each time. That is dependent on your web server. If the same apache/mod-php process lives through several invocations of the script, it won't reset the seed each time. But every php process will start with the same seed. If php is invoked as an external cgi, seed will always be the same. So... always seed!
php_public at macfreek dot nl
07-Oct-2001 11:52
The make_seed() function in the example code is VERY bad, and is in fact responsible for seeding always the same value, so that the output of rand() is the same with every page reload (!)

ALWAYS use:
(double)microtime()*1000000

See for more details my note on the mt_srand() page [ function.mt_srand.php ]
houtex_boy-at-yahoo-dot-com
06-Oct-2001 08:52
The above function ^ will never execute anything. It should be something like this:

function my_srand($seed = '')
{
   static $wascalled = FALSE;
   if (!$wascalled){
       $seed = $seed === '' ? (double) microtime() * 1000000 : $seed;
       srand($seed);
       $wascalled = TRUE;
   }
}

&nbsp;
ceo at l-i-e dot com (fka richard at zend dot com)
25-Aug-2001 01:58
Here is a way to be sure you only call srand once:

function my_srand($seed = ''){
   static $wascalled = TRUE;
   if (!$wascalled){
       $seed = $seed === '' ? (double) microtime() * 1000000 : $seed;
       srand($seed);
   }
}
15-Aug-2001 01:14
I have a ramdon circulater that changes a piece of text once a day, and I use the following code to make sure the see is unique enough.

$tm = time();
$today = mktime(0, 0, 0, (int)date("n", $tm), (int)date("j", $tm), (int)date("Y", $tm));                                                 
srand($today / pi());

The pi works wonders for the whole thing and it works like a charm. Any other big decimal number will do as well, but pi is the most common "big" number.
akukula at min dot pl
14-Aug-2001 10:14
Calling srand((double)microtime()*1000000),
then $a=rand(1000000,9999999), then srand((double)microtime()*$a)
adds nothing to the entrophy: the execution time of rand and srand is
constant, so the second microtime() produces nothing really fascinating. You may safely use just the first srand().
vonStahl at NOPE2SPAM dot ratio dot net
27-Jul-2001 08:32
How about<br>
<?
srand
((double)microtime()*1000000);
$seed = rand(1000000,9999999);
srand((double)microtime()*$seed);
$yadda = rand (1,100);
?><br>
I used this in a test run with 1,000.000 calls for $yadda. Processing time increased by 0.0000061 seconds compared to a simple "srand((double)microtime()*1000000);"
$yadda had the value of each number between 1 and 100 for between 0.99999122% and 1.00000872% of all calls. That's random and fast enough for me. :)
rjones at ditzed dot org
30-May-2001 03:02
As a sidenote on the usage of srand():

If you are making use of modular programming, it is probably better to try and call the srand routine from the parent script than from any modules you may be using (using REQUIRE or INCLUDE).
This way you get around the possibility of calling srand() more than once from different modules.

The flaw in this solution, of course, is when using modules produced by another programmer, or when producing modules for another programmer.
You cannot rely on another programmer calling the srand function before calling the modular function, so you would have to include the srand function inside the module in this case.

If you produce modules for use by other programmers then it is good practice to documentise the fact you have already called the srand function.
Or if you use a modular function produced by someone else, check their documentation, or check their source code.
rjones at ditzed dot org
30-May-2001 02:41
Use the srand() seed "(double)microtime()*1000000" as mentioned by the richard@zend.com at the top of these user notes.

The most notable effect of using any other seed is that your random numbers tend to follow the same, or very similar, sequences each time the script is invoked.

Take note of the following script:

  srand($val);

  echo rand(0, 20) . ", ";
  echo rand(0, 20) . ", ";
  echo rand(0, 20) . ", ";
  echo rand(0, 20) . ", ";
  echo rand(0, 20);

If you seed the generator with a constant, say; the number 5 ($val = 5), then the sequence generated is always the same, in this case (0, 18, 7, 15, 17) (for me at least, different processors/processor speeds/operating systems/OS releases/PHP releases/webserver software may generate different sequences).

If you seed the generator with time(), then the sequence is more random, but invokations that are very close together will have similar outputs.

As richard@zend.com above suggests, the best seed to use is (double) microtime() * 1000000, as this gives the greatest amount of psuedo-randomness. In fact, it is random enough to suit most users.
In a test program of 100000 random numbers between 1 and 20, the results were fairly balanced, giving an average of 5000 results per number, give or take 100. The deviation in each case varied with each invokation.
MakeMoolah at themail dot com
29-Jan-2001 07:16
Sorry about that...  ok, forget have of what I said up there ^.

The code that would prove my example is this:

srand(5);
echo(rand(1, 10));
srand(5);
echo(rand(1, 10));
srand(5);
echo(rand(1, 10));

Each time you SHOULD get the same answer, but if you did this:

srand(5);
echo(rand(1, 10));
echo(rand(1, 10));
echo(rand(1, 10));

then the answers would be different, and you'd be letting the random number formula do it's duty.
hagen at von-eitzen dot de
10-Oct-2000 06:51
It is REALLY essential to make sure that srand is called only once.
This is a bit difficult if the call is hidden somewhere in third-party code you include. For example, I used a standard banner script that *seemed* to work well putting
three random banners in one frame. But in the long run, the choice appeared
somewhat biased - probably because srand was called once per banner, not
once per run.
It would be nice if the random number generator worked like in PERL: If You use the random function without having called srand ever before in a script,
srand is invoked before (and automatically with a nice seed, hopefully).
I suggest that one should do something like this:
<pre>
if (!$GLOBALS["IHaveCalledSrandBefore"]++) {
  srand((double) microtime() * 1000000);
}
</pre>
(Depending on the situation, one might also work with a static variable instead)
richard at zend dot com
06-Oct-2000 03:02
*ALWAYS* use
(double)microtime()*1000000
as your seed.
Do *NOT* just use time().  Do not add an extra 0 to make it "bigger".

Take care to call srand() only *ONCE* per script.

Calling
(double)microtime()*1000000
once, and only once, per script gives you the maximum "randomness" you can get.

Anything else is sub-standard.  If you want to understand why, there's a lot of reading you need to do...  I don't know enough to point you to the best text to get started on this reading.  For now, just trust the PHP Developers, okay?