我想这是我关于 SO 的第一个问题。
我目前正在一个网站上工作,我必须为彩票生成 1 到 29 之间的 6 个数字(每个最大值之一)。由于它们可以按任何顺序排列,因此我只是在之后对它们进行排序。
如果我没记错的话,应该是(29*28*27*26*25*24)/6! = 475020
不同的可能组合。
我尝试了不同的生成序列的方法,使用 mt_rand 或 random_int(来自 random_compat )但是当我用大约 10k 次迭代测试它时,我总是得到大约 100 个重复项,即使它们是 465k 组合仍然可用。
以下是我一直在尝试的代码示例:
// Using an array and mt_rand (or random_int, giving same results)
// Also tried shuffling the array instead of simply reindexing it, not better
$values = range(1, 29);
while(count($values) > 6) {
unset($values[mt_rand(0, count($values) - 1)]);
$values = array_values($values);
}
// Creating the array from random numbers (same results using random_int)
$values = array();
while (count($values) < 6) {
$r = mt_rand(1, 29);
if (in_array($r, $values)) {
continue;
} else {
$values[] = $r;
}
}
很好...我的问题是:
- 有没有办法改进我目前正在做的事情?
- 事情会这样吗,我必须处理它?</li>
- 我是不是做错了?
谢谢!
琳。
PS: 翻了很多问题,没找到满足我需求的东西,如果我看的不够好,请见谅!
只是为了说明一些事情:使用 random_int(利用/dev/urandom 或 openssl_random_pseudo_bytes)不会改善任何事情,我认为会。如果可能,我不想使用任何外部 API(如 random.org)。
最佳答案
Using random_int (which makes use of /dev/urandom or openssl_random_pseudo_bytes) doesn't improve anything, which I thought would.
当然可以,只是您无法通过视觉识别。 mt_rand()
和 rand()
只允许大约 232 可能的种子和 232 可能的输出,而且,大多数重要的是,具有确定性序列:if you know a few outputs, you can predict the rest until it's reseeded .
您的操作系统的 CSPRNG 没有任何此类限制。了解一些 random_int()
输出(在 PHP 中,在 32 位系统上限制为 232 可能的值,在 64 位系统上限制为 264 -位系统)不会给你任何关于 future 输出的信息。
I'm currently working on a website and I have to generate 6 numbers between 1 and 29 (one of each max) for a lottery. As they can be in any order, I simply sort them afterwards.
好吧,这是个好主意。你肯定想要一个 CSPRNG。
when I test it with something like 10k iterations, I always get around 100 duplicates, even though they are like 465k combinations still available.
正如其他人所指出的,这是 birthday problem/paradox在玩。
如果您需要解决方案,请尝试以下操作:
function random_unique_select($num, array $possible_values)
{
$sizeof = count($possible_values);
if ($num > $sizeof) {
throw new InvalidArgumentException('$num is too large');
}
$selected = [];
for ($i = 0; $i < $num; ++$i) {
// Grab a random int [0, ... N - 1]
$r = random_int(0, $sizeof - 1);
// Copy the selected value into $selected
$selected[] = $possible_values[$r];
// Delete it from the range of possible values
unset($possible_values[$r]);
// N has grown smaller by 1
--$sizeof;
// Reset keys; we want this to be zero-indexed.
$possible_values = array_values($possible_values);
}
return $selected;
}
$lottery = random_unique_select(6, range(1,29));
演示:
- http://3v4l.org/Hb97A (单程;使用
openssl_random_pseudo_bytes()
) - http://3v4l.org/E7cb5 (100,000 次迭代 -> 非常少量的重复)
关于PHP - 改进随机数序列生成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31825955/