|
srand
Seed the random number generator
(PHP 4, PHP 5)
Example 1162. srand() example<?php Related Examples ( Source code ) » srand Examples ( Source code ) » mt_rand with no arguments Examples ( Source code ) » mt_rand with two arguments Examples ( Source code ) » Break in Nested Loops Code Examples / Notes » srandoffice
[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. rjones
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. trobinson-a-t-gksystems-d-o-t-com
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
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
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; } } mlwmohawk
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. makemoolah
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. php
Richard's statement, that calling srand more than once per script will impair you chance to get a true random number, is not necessarily correct. In fact using srand more than once can even improve randomness if you understand how. The rand function uses a certain algorithm to calculate a number out of the seed given to srand. This algorithm, of course, is always the same, so without knowing the seed (which is assumed to be random) you can calculate any value returned by rand other than the first one if you know the first one. The chances to do so get better the higher the range of your random number is (and are pretty good if the range of the random number exceeds the possible range of the seed). In the following example the range of the desired random number is 10 times higher than the possible range of the seed: <? list($usec, $sec) = explode(" ", microtime()); srand((int)($usec*10)); $rand_value = rand(0, 99); echo($rand_value." "); $rand_value = rand(0, 99); echo($rand_value." "); $rand_value = rand(0, 99); echo($rand_value." "); ?> The code will return 3 numbers. Execute the code several times and write down each set of numbers, you will notice that after a short time you will know the second and the third number by only seeing the first one and compare it to what you've written down. All that without knowing the random seed! Of course seeding with (double)microtime()*1000000 gives a 100,000 times higher range, but if the range of the random numbers you want to generate was 100,000 times higher too, it's just a matter of time for someone being able to predict all your random numbers after the first one. But simply calling srand in between the rands wouldn't do the trick either, because the execution time of the code in between the srands is highly predictable. The key is to do something before each call of srand, which has a real random time of execution. Requesting a website from another server would be such a thing (can also be a SQL request or something). <? list($usec, $sec) = explode(" ", microtime()); srand((int)($usec*10)); $rand_value = rand(0, 99); echo($rand_value." "); $foo=file_get_contents ("http://www.google.com/search?q=sea rch+term+does+not+matter&hl=en"); list($usec, $sec) = explode(" ", microtime()); srand((int)($usec*10)); $rand_value = rand(0, 99); echo($rand_value." "); $foo=file_get_contents ("http://www.google.com/search?q=sea rch+term+still+does+not+matter&hl=en"); list($usec, $sec) = explode(" ", microtime()); srand((int)($usec*10)); $rand_value = rand(0, 99); echo($rand_value." "); ?> You can probably execute this code a thousand times with hardly getting any set of 3 numbers repeated. Try what you did with the other code snippet above and note that you improved randomness by using srand more than once. Via http://www.capuzza.com/detail.php?ID=115293 bootc
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. codaholics dot com
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 :) davidaylmer zebra gmail.com zebra =
Just for the convienience of others... 1000003 is a prime number So (double)microtime()*1000003 may work better for some applications. sinister
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. hagen
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) ceo
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 \n"; } $stats[$choice]++; } reset($stats); while (list($num, $count) = each($stats)){ echo "$num: $count \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? greenmonkey
if u r looking for a good PRNG try google with "Mersenne Twister"
no
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; } 15-aug-2001 06: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. vonstahl
How about <? srand((double)microtime()*1000000); $seed = rand(1000000,9999999); srand((double)microtime()*$seed); $yadda = rand (1,100); ?> 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. :) vinod
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 corey
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! } ceo
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); } } akukula
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(). rjones
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. edublancoa
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. richard
*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? |