I want to get n
random numbers(e.g n=16)(whole numbers) between 1 to 5(including both) so that average is x.
x can be any value between (1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5).
I am using PHP.
e.g.
Suppose I have average x= 3.
Then required 16 whole numbers between 1 to 5(including both).
like (1,5,3,3,3,3,2,4,2,4,1,5,1,5,3,3)
Update:
if x=3.5 means average of 16 numbers should be between 3.5 to 4.
and if x=4 means average of 16 numbers should be between 4 to 4.5
and if x=5 means all numbers are 5
This answer allows any value for the target average (regardless of whether n is odd or even) and avoids the use of recursion to optimize performance.
The Function
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;
}
}
Example Output:
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
If I got it right, I would suggest you to have the average, than generate a number below the average and then to add a number with the same distance from average to the other side. For example, average 4 has the maximum border distance of 1 from nearest limit 5, so you should generate between 3, 4, 5. If 3 is generated - put 5 next. If 5, then 3. If 4 - put 4 next. And so on 8 times.
The best way to solve it is to put it this way:
average = sum of all numbers / amount of numbers, therefor,
average * amount = sum, as Michael said. Now, if your sum is not integer - you will have no solution for this one.
It means that no matter, which method to use - mine, or Michael's. The difference is Michael's method doubles randomness with larger execution time.