我需要在给定范围内生成 x 数量的随机奇数。我知道这可以通过简单的循环来实现,但我不确定哪种方法是最好的,是否有更好的数学方法来解决这个问题。
编辑:我也不能多次拥有相同的号码。
在一半范围内生成 x 个整数值,并且对于每个值将其加倍并加 1。
回答修改后的问题: 1) 生成范围内的候选者列表,将它们洗牌,然后取第一个 x。或者 2) 根据我最初的建议生成值,如果生成的值在已生成值的列表中,则拒绝并重试。
如果 x 是范围的很大一部分,则第一个会更好,如果 x 相对于范围较小,则后者会更好。
附录:应该早点想到这种方法,它是基于条件概率的。我不知道 php(我来自“随机”标签),所以我将其表示为伪代码:
generate(x, upper_limit)
loop with index i from upper_limit downto 1 by 2
p_value = x / floor((i + 1) / 2)
if rand <= p_value
include i in selected set
decrement x
return/exit if x <= 0
end if
end loop
end generate
x
是要生成的所需值的数量,upper_limit
是该范围内的最大奇数,并rand
生成一个介于 0 和 1 之间的均匀分布的随机数。基本上,它逐步遍历候选奇数集,并根据您仍然需要多少值以及还剩下多少候选值来接受或拒绝每个奇数。
我已经对此进行了测试,它确实有效。它比改组需要更少的中间存储,并且比原始接受/拒绝需要更少的迭代。
生成范围内的元素列表,在随机系列中删除您想要的元素。重复 x 次。
或者您可以生成一个范围内奇数的数组,然后进行随机播放
生成很简单:
$range_array = array();
for( $i = 0; $i < $max_value; $i++){
$range_array[] .= $i*2 + 1;
}
随机播放
shuffle( $range_array );
拼接出第 x 个元素。
$result = array_slice( $range_array, 0, $x );
这是一个完整的解决方案。
function mt_rands($min_rand, $max_rand, $num_rand){
if(!is_integer($min_rand) or !is_integer($max_rand)){
return false;
}
if($min_rand >= $max_rand){
return false;
}
if(!is_integer($num_rand) or ($num_rand < 1)){
return false;
}
if($num_rand <= ($max_rand - $min_rand)){
return false;
}
$rands = array();
while(count($rands) < $num_rand){
$loops = 0;
do{
++$loops; // loop limiter, use it if you want to
$rand = mt_rand($min_rand, $max_rand);
}while(in_array($rand, $rands, true));
$rands[] = $rand;
}
return $rands;
}
// let's see how it went
var_export($rands = mt_rands(0, 50, 5));
代码未经测试。刚写的。可以改进一点,但这取决于你。
此代码在区间 [1, 20] 中生成 5 个奇数唯一数。根据需要更改 $min、$max 和 $n = 5。
<?php
function odd_filter($x)
{
if (($x % 2) == 1)
{
return true;
}
return false;
}
// seed with microseconds
function make_seed()
{
list($usec, $sec) = explode(' ', microtime());
return (float) $sec + ((float) $usec * 100000);
}
srand(make_seed());
$min = 1;
$max = 20;
//number of random numbers
$n = 5;
if (($max - $min + 1)/2 < $n)
{
print "iterval [$min, $max] is too short to generate $n odd numbers!\n";
exit(1);
}
$result = array();
for ($i = 0; $i < $n; ++$i)
{
$x = rand($min, $max);
//not exists in the hash and is odd
if(!isset($result{$x}) && odd_filter($x))
{
$result[$x] = 1;
}
else//new iteration needed
{
--$i;
}
}
$result = array_keys($result);
var_dump($result);