fizix Posted September 16, 2009 Share Posted September 16, 2009 I hope somebody can help me with this because I'm at wit's end: I have a script that generates a random number. I don't want it to ever generate the same random number twice so I'm seeding the rand function with an incrementing number. However, after a certain point, it generates a duplicate random number anyway. Here's the function to prove it: $test = array(); set_time_limit(200); for ($i=10;$i<100000;$i++) { srand($i); $number = rand(); if (in_array($number, $test)) { die("Found dupe at iteration number $i<br />\nNumber is $number"); } else { $test[] = $number; } $runtime = time() - $starttime; } The output I get when running the script under Apache in Windows is this: Found dupe at iteration number 32778 Number is 16507 However, when I run the script in a Linux environment I don't seem to have the problem (although it times out before it gets to the 200 second time limit). Anybody have any ideas how to fix this? By the way, you'll need to have "suhosin.srand.ignore = Off" in your php.ini file to the code above. Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/ Share on other sites More sharing options...
RussellReal Posted September 16, 2009 Share Posted September 16, 2009 it is not windows or linux's problem, if you seed the random number generator the same number you'll get the same result multiple times or more frequently if that. because NO computer generated number is completely random, and relies on certain factors which change rapidly for example system ticks. miliseconds of script running, miliseconds of server uptime, anything which changes constantly and rapidly is usually what seeds a random number, seeding an incrementing number will not yield too much of a random number array since the seeds are very very close together therefore you'll more than likely run into same numbers output, but then again logically.. random numbers could return all the same number every time.. just pretty rare.. so running into duplicate results isn't that unlikely Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-919614 Share on other sites More sharing options...
MatthewJ Posted September 16, 2009 Share Posted September 16, 2009 Random does not mean unique Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-919618 Share on other sites More sharing options...
Daniel0 Posted September 16, 2009 Share Posted September 16, 2009 When finding a duplicate, just subtract 1 from $i and move on. That'll give you the required number of random integers. Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-919621 Share on other sites More sharing options...
fizix Posted September 16, 2009 Author Share Posted September 16, 2009 When finding a duplicate, just subtract 1 from $i and move on. That'll give you the required number of random integers. Unfortunately I can't do this because I'll have multiple scripts running at the same time and none of them should be generating the same number. I can't store all the numbers in a database either... the database would get way too big way too quickly. Does anybody know of a way to generate a random number, without duplicates, and not log all the numbers that have already been generated? Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-919661 Share on other sites More sharing options...
RussellReal Posted September 16, 2009 Share Posted September 16, 2009 if you need something unique for your numbers.. generate an md5 hash for each integer Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-919670 Share on other sites More sharing options...
fizix Posted September 16, 2009 Author Share Posted September 16, 2009 if you need something unique for your numbers.. generate an md5 hash for each integer That didn't help. I changed my test function to this: $test = array(); $starttime = time(); for ($i=0;$i<100000;$i++) { srand($i); if ($runtime % 30 == 0) set_time_limit(200); $number = md5(rand()); if (in_array($number, $test)) { die("Found dupe at iteration number $i<br />\nNumber is $number"); } else { $test[] = $number; } $runtime = time() - $starttime; } And got: Found dupe at iteration number 32768 Number is 827ccb0eea8a706c4c34a16891f84e7b Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-919682 Share on other sites More sharing options...
fizix Posted September 17, 2009 Author Share Posted September 17, 2009 Anybody else have any ideas? Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920155 Share on other sites More sharing options...
mattal999 Posted September 17, 2009 Share Posted September 17, 2009 if you need something unique for your numbers.. generate an md5 hash for each integer That didn't help. I changed my test function to this: $test = array(); $starttime = time(); for ($i=0;$i<100000;$i++) { srand($i); if ($runtime % 30 == 0) set_time_limit(200); $number = md5(rand()); if (in_array($number, $test)) { die("Found dupe at iteration number $i<br />\nNumber is $number"); } else { $test[] = $number; } $runtime = time() - $starttime; } And got: Found dupe at iteration number 32768 Number is 827ccb0eea8a706c4c34a16891f84e7b Well then you could md5 it with random salts. Example: $test = array(); $starttime = time(); for ($i=0;$i<100000;$i++) { srand($i); if ($runtime % 30 == 0) set_time_limit(200); $salt1 = rand(); srand($i + rand()); $salt2 = rand(); srand($i - rand()); $number = md5($salt1 . rand() . $salt2); if (in_array($number, $test)) { die("Found dupe at iteration number $i<br />\nNumber is $number"); } else { $test[] = $number; } $runtime = time() - $starttime; } Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920158 Share on other sites More sharing options...
kickstart Posted September 17, 2009 Share Posted September 17, 2009 Does anybody know of a way to generate a random number, without duplicates, and not log all the numbers that have already been generated? If it is truely a random number then it will inevitably have duplicates. Does it need to be a large and complex number? Or would just a count work? You could have a table with a single integer autonumber column and just do an insert (of NULL) and then get the last inserted key (in Oracle you could just use a sequence, but MySQL doesn't support them). To stop the table just delete old inserts regularly (possibly triggered by inserts to the table). If you want to mix it up a bit then just hash that number. All the best Keith Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920165 Share on other sites More sharing options...
Mark Baker Posted September 17, 2009 Share Posted September 17, 2009 has uniqid() been deprecated or something? Otherwise surely this is the obvious function. Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920213 Share on other sites More sharing options...
fizix Posted September 17, 2009 Author Share Posted September 17, 2009 has uniqid() been deprecated or something? Otherwise surely this is the obvious function. How can I use uniqid to seed the rand function? Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920233 Share on other sites More sharing options...
fizix Posted September 17, 2009 Author Share Posted September 17, 2009 Does anybody know of a way to generate a random number, without duplicates, and not log all the numbers that have already been generated? If it is truely a random number then it will inevitably have duplicates. Does it need to be a large and complex number? Or would just a count work? You could have a table with a single integer autonumber column and just do an insert (of NULL) and then get the last inserted key (in Oracle you could just use a sequence, but MySQL doesn't support them). To stop the table just delete old inserts regularly (possibly triggered by inserts to the table). If you want to mix it up a bit then just hash that number. All the best Keith Wouldn't this basically do the same thing as my for loop? Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920236 Share on other sites More sharing options...
kickstart Posted September 17, 2009 Share Posted September 17, 2009 Hi No, because it appears you are just using your loop to test when the number as a seed causes a duplicate. If you just use the id then no need to use it as a seed or anything. Just use it as it is. Why does the number need to be random? The suggestion of uniqueid() appears to give you exactly what you want without any need for any extra random number generation. All the best Keith Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920246 Share on other sites More sharing options...
fizix Posted September 17, 2009 Author Share Posted September 17, 2009 if you need something unique for your numbers.. generate an md5 hash for each integer That didn't help. I changed my test function to this: $test = array(); $starttime = time(); for ($i=0;$i<100000;$i++) { srand($i); if ($runtime % 30 == 0) set_time_limit(200); $number = md5(rand()); if (in_array($number, $test)) { die("Found dupe at iteration number $i<br />\nNumber is $number"); } else { $test[] = $number; } $runtime = time() - $starttime; } And got: Found dupe at iteration number 32768 Number is 827ccb0eea8a706c4c34a16891f84e7b Well then you could md5 it with random salts. Example: $test = array(); $starttime = time(); for ($i=0;$i<100000;$i++) { srand($i); if ($runtime % 30 == 0) set_time_limit(200); $salt1 = rand(); srand($i + rand()); $salt2 = rand(); srand($i - rand()); $number = md5($salt1 . rand() . $salt2); if (in_array($number, $test)) { die("Found dupe at iteration number $i<br />\nNumber is $number"); } else { $test[] = $number; } $runtime = time() - $starttime; } Still didn't work. :'( Found dupe at iteration number 32768 Number is 40be5f590f625b8cff8072df0026756d Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920247 Share on other sites More sharing options...
fizix Posted September 17, 2009 Author Share Posted September 17, 2009 Hi No, because it appears you are just using your loop to test when the number as a seed causes a duplicate. If you just use the id then no need to use it as a seed or anything. Just use it as it is. Why does the number need to be random? The suggestion of uniqueid() appears to give you exactly what you want without any need for any extra random number generation. All the best Keith uniqueid gives me no control over the length of the string I'm generating, nor does it guarantee that I would have duplicates. Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920252 Share on other sites More sharing options...
kickstart Posted September 17, 2009 Share Posted September 17, 2009 Hi What do you need the string for that you need to control the length of it? Does it need to be random rather than just unique? If you truely need a unique and random id of a specified length then I think you will have to do it by making a random one up and then checking it hasn't been used. All the best Keith Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920259 Share on other sites More sharing options...
fizix Posted September 17, 2009 Author Share Posted September 17, 2009 Hi What do you need the string for that you need to control the length of it? Does it need to be random rather than just unique? If you truely need a unique and random id of a specified length then I think you will have to do it by making a random one up and then checking it hasn't been used. All the best Keith Yes, it needs to be random and unique. I'm basically generating a bunch of random IP addresses and I don't want to generate the same one twice. I can't keep a list of addresses I've already generated because I'll have multiple processes running at the same time and the database containing the addresses would get WAY too big WAY too quickly (trust me, I've already tried). Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920272 Share on other sites More sharing options...
mikesta707 Posted September 17, 2009 Share Posted September 17, 2009 you can use array_unique on your array of random numbers. Random number generators will run into duplicate entries at some point, so perhaps randomly generated numbers isn't what you want. also uniqueid() seems to be exactly what you want as people have said.. why dont you use that? Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920273 Share on other sites More sharing options...
fizix Posted September 17, 2009 Author Share Posted September 17, 2009 you can use array_unique on your array of random numbers. Random number generators will run into duplicate entries at some point, so perhaps randomly generated numbers isn't what you want. also uniqueid() seems to be exactly what you want as people have said.. why dont you use that? Read UP ^ Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920275 Share on other sites More sharing options...
mattal999 Posted September 17, 2009 Share Posted September 17, 2009 Attempt 2: $test = array(); $starttime = time(); for ($i=0;$i<100000;$i++) { srand($i.strtotime(date())); if ($runtime % 30 == 0) set_time_limit(200); $number = rand(); if (in_array($number, $test)) { $i--; //die("Found dupe at iteration number $i<br />\nNumber is $number"); } else { $test[] = $number; } $runtime = time() - $starttime; } Should work as expected. Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920288 Share on other sites More sharing options...
kickstart Posted September 17, 2009 Share Posted September 17, 2009 Hi If it a tricky one then. IP address is just 4 numbers each from 0 to 255, so just really a 4 byte unsigned integer (or 4 unsigned tinyints). Not that large to store lots (you could store evey one possible in about 16gb). However possibly not manageable to search them each time. Afraid I am not sure I can see a solution without storing them to check against duplicates. All the best Keith Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920291 Share on other sites More sharing options...
fizix Posted September 17, 2009 Author Share Posted September 17, 2009 Hi If it a tricky one then. IP address is just 4 numbers each from 0 to 255, so just really a 4 byte unsigned integer (or 4 unsigned tinyints). Not that large to store lots (you could store evey one possible in about 16gb). However possibly not manageable to search them each time. Afraid I am not sure I can see a solution without storing them to check against duplicates. All the best Keith I think you're right... I give up. :'( Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920295 Share on other sites More sharing options...
kickstart Posted September 17, 2009 Share Posted September 17, 2009 Hi If you could put up with them being non random it would be possible. All the best Keith Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920297 Share on other sites More sharing options...
fizix Posted September 17, 2009 Author Share Posted September 17, 2009 Hi If you could put up with them being non random it would be possible. All the best Keith I don't want to create them sequentially but maybe if I assigned each process a group of IP addresses (say 2000 at a time) and then told it to select from that group at random and removed each address I tried from the group as I went it would still be quasi-random and they would all be unique... Quote Link to comment https://forums.phpfreaks.com/topic/174481-rand-and-mt_rand-arent-random-on-win32/#findComment-920304 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.