我希望得到n
个随机数(例如n = 16)(整数)介于1到5之间(包括两者),以便平均值为x。
x可以是(1,1.5,2,2.5,3,3.5,4,4.5,5)之间的任何值。
我正在使用PHP。
e.g。 假设我有平均x = 3.
然后需要16个1到5之间的整数(包括两者)。 像(1,5,3,3,3,3,2,4,2,4,1,5,1,5,3,3)
更新
如果x = 3.5意味着16个数字的平均值应该在3.5到4之间 如果x = 4则意味着16个数字的平均值应在4到4.5之间 如果x = 5则表示所有数字都是5
答案 0 :(得分:4)
此答案允许目标平均值的任何值(无论n是奇数还是偶数),并避免使用递归来优化性能。
功能
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
答案 1 :(得分: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());
答案 2 :(得分:1)
我会像这样实现它:
答案 3 :(得分:1)
我为此编写了JS实现:
function getRandom(min, max) {
return Math.random() * (max - min) + min;
}
function getArr(size, avg, min, max) {
let arr = [];
let tmax = max;
let tmin = min;
while (arr.length < size) {
const variable1 = +getRandom(min, tmax).toFixed(1);
let variable2 = +(avg * 2 - variable1).toFixed(1);
if (variable2 < min) {
tmax = max - (min - variable2);
variable2 = min;
} else if (variable2 > max) {
tmin = min + (variable2 - max);
variable2 = max;
} else {
tmax = max;
tmin = min;
}
arr = arr.concat([variable1, variable2]);
}
let sumErr = arr.reduce((a, b) => a + b, 0) - avg * size;
if (sumErr > 0) {
arr = arr.map((x) => {
if (x > min && sumErr > 0.001) {
let maxReduce = x - min;
if (maxReduce > sumErr) {
const toReturn = +(x - sumErr).toFixed(1);
sumErr = 0;
return toReturn;
} else {
sumErr -= maxReduce;
return min;
}
}
return x;
});
} else {
arr = arr.map((x) => {
if (x < max && sumErr < -0.001) {
let maxAdd = max - x;
if (maxAdd > Math.abs(sumErr)) {
const toReturn = +(x + Math.abs(sumErr)).toFixed(1);
sumErr = 0;
return toReturn;
} else {
sumErr += maxAdd;
return max;
}
}
return x;
});
}
return arr.sort(() => Math.random() - 0.5);
}
const output = getArr(40, 2.01, 0.5, 2.5)
const outputAvg = output.reduce((a, b) => a + b, 0) / 40
console.log(`givenAvg: ${2.01} outputAvg: ${outputAvg}`)
console.log(output)
答案 4 :(得分:0)
如果我做对了,我会建议你得到平均值,而不是产生一个低于平均值的数字,然后添加一个从平均到另一边的距离相同的数字。例如,平均值4的最大边界距离为1,距离最近限制为5,因此您应该生成3,4,5之间。如果生成3,则接下来放5。如果是5,那么3.如果4 - 接下来放4。等8次。
解决问题的最佳方法是这样说:
平均值=所有数字/数量之和,因此, 迈克尔说,平均值*金额=总和。现在,如果你的总和不是整数 - 你将无法解决这个问题。
这意味着无论使用哪种方法 - 我的,还是迈克尔的。不同的是迈克尔的方法使随机性加倍,执行时间更长。