Php 获取两个平均值为'x'的数字之间的'n'随机值`

Php 获取两个平均值为'x'的数字之间的'n'随机值`,php,algorithm,random,range,average,Php,Algorithm,Random,Range,Average,我想得到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,如果我做对

我想得到
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,如果我做对了,我建议你取平均值,然后在平均值下生成一个数字,然后再加上一个从平均值到另一边距离相同的数字。例如,平均值4与最近的极限值5之间的最大边界距离为1,因此应在3、4、5之间生成。如果生成了3,则下一步放入5。如果是5,那么是3。如果4-下一个放4。如此类推8次

最好的解决办法是这样说:

平均值=所有数字的总和/数字的数量,因此, 正如迈克尔所说,平均*金额=总和。现在,如果你的和不是整数-你将没有这个问题的解决方案


这意味着不管用哪种方法——我的还是迈克尔的。不同之处在于,Michael的方法将随机性加倍,执行时间更长。

编辑:我重新编写了此方法,以避免递归调用函数

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

此答案允许目标平均值的任何值(无论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;
  }
}

我会这样实施:

  • 选择n个随机数
  • 计算平均数
  • 从n个随机数中随机选择一个
  • 根据当前平均值高于还是低于x,从数字中加上或减去1
  • 从步骤2重复,直到当前平均值为x(或足够接近)

  • 我已经为此编写了JS实现:

    函数getRandom(最小值、最大值){ 返回Math.random()*(max-min)+min; } 函数getArr(大小、平均值、最小值、最大值){ 设arr=[]; 设tmax=max; 设tmin=min; while(arr.length最大值){ tmin=最小值+(变量2-最大值); 变量2=最大值; }否则{ tmax=最大值; tmin=min; } arr=arr.concat([variable1,variable2]); } 让sumErr=arr.reduce((a,b)=>a+b,0)-avg*大小; 如果(苏美尔>0){ arr=arr.map((x)=>{ 如果(x>min&&sumErr>0.001){ 设maxReduce=x-min; 如果(maxReduce>sumErr){ 常数toReturn=+(x-苏美尔).toFixed(1); 苏美尔=0; 回归回归; }否则{ sumErr-=maxReduce; 返回最小值; } } 返回x; }); }否则{ arr=arr.map((x)=>{ 如果(xMath.abs(sumErr)){ constToReturn=+(x+Math.abs(sumErr)).toFixed(1); 苏美尔=0; 回归回归; }否则{ sumErr+=maxAdd; 返回最大值; } } 返回x; }); } 返回arr.sort(()=>Math.random()-0.5); } 常量输出=getArr(40,2.01,0.5,2.5) const outputAvg=output.reduce((a,b)=>a+b,0)/40 log(`givenAvg:${2.01}outputAvg:${outputAvg}`)
    console.log(output)
    你能展示一些你也曾想过的想法吗?如果数字是真正随机的,那么真正的平均值只能是3…添加一个要求数字达到指定平均值的约束将消除随机性。例如,在您的示例中,您可以从该组中选择8个随机数,然后为每个数找到另一个数,其中两个数的平均值为3。这应该行得通,但你们不再有16个随机值了,你们永远也不会。我更新了问题。那个么你们到目前为止到底尝试了什么?但我可以得到平均值3.5,1.5。我需要随机数作为整数。仍然有效-如果你的平均数是1.5,那么你需要1和2,3.5需要3和4,或者2和5,1和6,等等。@Michael的建议仍然有效。你可以为此建立一个算法,但不会有随机性。@TheOx:我可以在(1,2,3,4,5)之间选择数字而不是6。好吧,忽略“1和6”部分。这种递归是危险的。对不起,伙计,你的建议是大海捞针。。。特别是,当你有一个浮动平均值。这在大多数情况下都没有解决办法。@MichaelSazonov,是的;我确实说过,只有当你知道有解决办法时,它才会起作用。@SomnathMuluk,你有什么错误吗?结果不正确?正在获取结果。1,5,4.5分不到。所以平均1,5意味着所有的数字都是一样的。应该只得到4.5的结果。在您的问题中:“如果x=3.5,则16个数字的平均值应在3.5到4之间。”只有当
    x
    不是整数且
    n
    是奇数时才会出现这种情况。例如,如果
    x
    =3.5和
    n
    =17,则17个整数需要相加到59.5,这是不可能的。所以平均值必须是4。这对我来说也很好。我只是编辑了一点点来生成随机数,而不是整数,但我发现这里
    $average=$i$总和/($i+1):($min+$max)/2冗余是否正常工作:)-
    
    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