2012-03-30 3 views
1

Я хочу получить n случайные числа (например, n = 16) (целые числа) от 1 до 5 (включая оба), так что среднее значение равно x.Получите «n» случайные значения между двумя числами со средним значением `x`

x может быть любым значением между (1, 1,5, 2, 2,5, 3, 3,5, 4, 4,5, 5).

Я использую PHP.

например. Предположим, что у меня средний x = 3.

Затем потребовалось 16 целых чисел от 1 до 5 (включая оба). как (1,5,3,3,3,3,2,4,2,4,1,5,1,5,3,3)

Update:

, если х = 3,5 посредством в среднем из 16 цифр должно быть в пределах от 3,5 до 4.
и если х = 4 означает, что в среднем из 16 цифр должно быть в пределах от 4 до 4,5
и если х = 5 означает, что все числа 5

+3

Вы могли бы показать некоторые идеи, которые вы также подумали? –

+2

Поистине среднее может быть только 3, если числа действительно случайны ... –

+0

Добавление ограничения, при котором номера требуют попадания в указанное среднее значение, удаляет случайность. Например, в вашем примере вы можете выбрать 8 случайных чисел из этой группы, затем для каждого номера найдите другой номер, где среднее из двух равно 3. Это должно работать, но у вас больше нет случайных значений для всех 16, и вы никогда не буду. – TheOx

ответ

3

Этот ответ позволяет любое значение для целевого среднего (независимо от того, п нечетное или четное), и позволяет избежать использования рекурсии для оптимизации производительности.

Функция

function getRandomNumbersWithAverage($target_average, $n, $min=1, $max=5) 
{ 

    if($min>$max) list($min, $max) = array($max, $min); 
    if($target_average<$min || $target_average>$max) return false; 
    else if($target_average==$min) return array_fill(0, $n, $min); 
    else if($target_average==$max) return array_fill(0, $n, $max); 

    if($n<1) return false; 
    else if($n==1) return array($target_average); 
    else 
    { 
    $numbers = array(); 
    for($i=0;$i<$n;$i++) 
    { 
     $sum = array_sum($numbers); 
     $average = $i ? $sum/($i+1) : ($min+$max)/2; 
     $contrived_number = $target_average*($i+1) - $sum; 
     // Last one must be contrived 
     if($i==$n-1) $new_number = ceil($contrived_number); // Round up 
     else 
     { 
     // The tolerance gets smaller with iteration 
     $tolerance = ($max-$min)*(1-($i/($n-1))); 
     $temp_min = ($contrived_number-$tolerance); 
     if($temp_min<$min) $temp_min = $min; 
     $temp_max = ($contrived_number+$tolerance); 
     if($temp_max>$max) $temp_max = $max; 
     $new_number = mt_rand($temp_min, $temp_max); 
     } 
     if($new_number==0) $new_number = 0; // Handle -0 
     $numbers[] = $new_number; 
    } 
    // Since the numbers get more contrived towards the end, it might be nice to shuffle 
    shuffle($numbers); 
    return $numbers; 
    } 
} 


Результат:

getRandomNumbersWithAverage(1, 12) 

produced the numbers: (1,1,1,1,1,1,1,1,1,1,1,1) having an average of: 1 


getRandomNumbersWithAverage(1.1, 13) 

produced the numbers: (1,1,1,1,1,1,1,4,1,1,1,0,1) having an average of: 1.1538461538462 


getRandomNumbersWithAverage(2.7, 14) 

produced the numbers: (3,3,2,5,1,2,4,3,3,2,3,3,3,1) having an average of: 2.7142857142857 


getRandomNumbersWithAverage(2.7, 15) 

produced the numbers: (3,3,4,3,4,2,1,1,3,2,4,1,5,1,4) having an average of: 2.7333333333333 


getRandomNumbersWithAverage(3.5, 16) 

produced the numbers: (5,5,4,3,1,5,5,1,2,5,3,3,4,4,4,2) having an average of: 3.5 


getRandomNumbersWithAverage(3.5, 17) 

produced the numbers: (5,2,3,5,4,1,2,3,5,4,5,4,2,3,5,3,4) having an average of: 3.5294117647059 


getRandomNumbersWithAverage(4, 18) 

produced the numbers: (3,5,5,3,5,5,3,4,4,4,5,2,5,1,5,4,5,4) having an average of: 4 


getRandomNumbersWithAverage(4.9, 19) 

produced the numbers: (5,5,5,5,7,5,5,5,5,6,5,3,5,5,3,5,5,5,5) having an average of: 4.9473684210526 


getRandomNumbersWithAverage(5, 20) 

produced the numbers: (5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5) having an average of: 5 


getRandomNumbersWithAverage(0.5, 10) 

does not produce numbers 


getRandomNumbersWithAverage(0, 9) 

does not produce numbers 


getRandomNumbersWithAverage(-1, 8) 

does not produce numbers 


getRandomNumbersWithAverage(5.5, 7) 

does not produce numbers 


getRandomNumbersWithAverage(6, 6) 

does not produce numbers 


getRandomNumbersWithAverage(6, 5, 1, 7) 

produced the numbers: (7,7,2,7,7) having an average of: 6 


getRandomNumbersWithAverage(6, 5, 1, 6) 

produced the numbers: (6,6,6,6,6) having an average of: 6 


getRandomNumbersWithAverage(3, 1) 

produced the numbers: (3) having an average of: 3 
+0

Работает очень хорошо. –

+0

он тоже отлично работает для меня я просто немного отредактировал для генерации случайных чисел, а не целого числа, но нашел, что здесь '$ average = $ i? $ sum/($ i + 1): ($ min + $ max)/2;' - это избыточность в противном случае работает штраф :) - –

0

Если бы я получил это право , Я предлагаю вам иметь среднее значение, чем генерировать число ниже среднего, а затем добавлять число с таким же расстоянием от среднего к другому. Например, среднее значение 4 имеет максимальное расстояние до границы от 1 до ближайшего предела 5, поэтому вы должны генерировать между 3, 4, 5. Если 3 генерируется - добавьте 5 дальше. Если 5, то 3. Если 4 - поставить 4 следующий. И так 8 раз.

Лучший способ решить это поставить его таким образом:

среднее = сумма всех чисел/количество чисел, для этого, средний * сумма = сумма, как сказал Майкл. Теперь, если ваша сумма не является целой, у вас не будет решения для этого.

Это означает, что независимо от того, какой метод использовать - мой или Майкл. Разница заключается в том, что метод Майкла удваивает случайность с большим временем выполнения.

+0

Но я могу иметь средний 3.5, 1.5. И мне нужны случайные числа в виде целых чисел. –

+0

Все еще работает - если у вас средний 1,5, тогда вам понадобится 1 и 2, 3,5 потребуются 3 и 4 или 2 и 5, 1 и 6 и т. Д. @ Предложение Майкла все еще выполняет эту работу. – TheOx

+0

Вы можете построить алгоритм для этого, но не было бы случайности. –

1

Редактировать: Я переписал это, чтобы избежать необходимости рекурсивно вызывать функцию.

<?php 

    /** 
    * Get an array of random numbers between the given range with a given average value 
    * 
    * @param integer $min 
    * @param integer $max 
    * @param integer $count 
    * @param integer|float $average 
    * @return boolean|array 
    */ 
    function getRandomNumbers($min = 1, $max = 5, $count = 16, $average = 3) 
    { 

    // Return FALSE if the range and/or the count are not all integers 
    if (!is_int($min) || !is_int($max) || !is_int($count)) 
    { 
     return FALSE; 
    } 

    // Round the average if the target total would be impossible 
    if (!is_int($count * $average)) 
    { 
     $average = round($average); 
    } 

    // Get the target total 
    $total = $count * $average; 

    // Return FALSE is the result is impossible 
    if ($min > $max || $min * $count > $total || $max * $count < $total) 
    { 
     return FALSE; 
    } 

    // Get the specified number of random integers 
    for ($i = 0; $i < $count; ++$i) 
    { 

     // Get a random number within the given range 
     $rand = mt_rand($min, $max); 

     // As a default do not continue 
     $cont = FALSE; 

     // Check to see if the random number is acceptable and if not change it until it is 
     while (!$cont) 
     { 

     // If the number is too high then decrease it by one 
     if (($total - $rand) - (($count - 1 - $i) * $min) < 0) 
     { 
      --$rand; 
     } 

     // Otherwise if the number is too low then increase it by one 
     elseif (($total - $rand) - (($count - 1 - $i) * $max) > 0) 
     { 
      ++$rand; 
     } 

     // Otherwise we can continue 
     else 
     { 
      $cont = TRUE; 
     } 

     } 

     // Store the number and minus it from the total 
     $total -= $result[] = $rand; 

    } 

    // Return the result 
    return $result; 

    } 

    // Output an array of random numbers 
    print_r(getRandomNumbers()); 
+0

Эта рекурсия была бы опасной. Извините, чувак, но ваше предложение ищет иглу в стоге сена ... Особенно, когда у вас средний поплавок. В большинстве случаев этого не будет. –

+0

Это не работает на моей машине. –

+0

@ Майкл Сазонов, да; Я сказал, что это будет работать, только если вы знаете, что есть решение. – MichaelRushton

1

Я бы реализовать это следующим образом:

  1. Выберите п случайных числа
  2. Вычислить средние
  3. Произвольно выбрать одну из п случайных чисел
  4. Добавить или вычесть 1 из числа, в зависимости от того, является ли текущее среднее выше или ниже х
  5. Повторить от шаг 2 до тех пор, пока текущее среднее значение не будет равно x (или достаточно близко)
Смежные вопросы