PHP在一个范围内生成x个随机奇数

I need to generate x amount of random odd numbers, within a given range. I know this can be achieved with simple looping, but I'm unsure which approach would be the best, and is there a better mathematical way of solving this.

EDIT: Also I cannot have the same number more than once.

Generate x integer values over half the range, and for each value double it and add 1.

ANSWERING REVISED QUESTION: 1) Generate a list of candidates in range, shuffle them, and then take the first x. Or 2) generate values as per my original recommendation, and reject and retry if the generated value is in the list of already generated values.

The first will work better if x is a substantial fraction of the range, the latter if x is small relative to the range.

ADDENDUM: Should have thought of this approach earlier, it's based on conditional probability. I don't know php (I came at this from the "random" tag), so I'll express it as pseudo-code:

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 is the desired number of values to generate, upper_limit is the largest odd number in the range, and rand generates a uniformly distributed random number between zero and one. Basically, it steps through the candidate set of odd numbers and accepts or rejects each one based how many values you still need and how many candidates still remain.

I've tested this and it really works. It requires less intermediate storage than shuffling and fewer iterations than the original acceptance/rejection.

Generate a list of elements in the range, remove the element you want in your random series. Repeat x times.

Or you can generate an array with the odd numbers in the range, then do a shuffle

Generation is easy:

$range_array = array();
for( $i = 0; $i < $max_value; $i++){
    $range_array[] .= $i*2 + 1;
}

Shuffle

shuffle( $range_array );

splice out the x first elements.

$result = array_slice( $range_array, 0, $x );

This is a complete solution.

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));

Code is not tested. Just wrote it. Can be improved a bit but it's up to you.

This code generates 5 odd unique numbers in the interval [1, 20]. Change $min, $max and $n = 5 according to your needs.

<?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!
";
    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);