【发布时间】:2013-06-16 23:09:58
【问题描述】:
我需要在给定范围内生成 x 个随机奇数。 我知道这可以通过简单的循环来实现,但我不确定哪种方法是最好的,是否有更好的数学方法来解决这个问题。
编辑:我也不能多次使用相同的号码。
【问题讨论】:
我需要在给定范围内生成 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);
【讨论】: