【问题标题】:How to make 5 random numbers with sum of 100 [duplicate]如何制作5个总和为100的随机数[重复]
【发布时间】:2011-11-09 11:43:21
【问题描述】:

您知道将整数分成... 5 组的方法吗? 每个组的总数必须是随机的,但它们的总数必须等于一个固定的数字。

例如我有“100”我想把这个数字分成

1- 20
2- 3
3- 34
4- 15
5- 18

编辑:我忘了说是的,平衡是一件好事。我想这可以通过使用 if 语句阻止任何超过 30 个实例的数字来完成。

【问题讨论】:

  • 这是可能的。你有尝试过吗?
  • 您对这部分的哪一部分有问题?你知道如何生成随机数吗?
  • 我不会为你做作业,但如果你想要 5 个组,我会先生成一个介于 1 和 100 - (5 - 1) 之间的随机数。
  • 这似乎不是 PHP 的问题?

标签: php random


【解决方案1】:

对于这里的一些答案,我的方法略有不同。我会根据您要合计的项目数创建一个宽松的百分比,然后随机加减 10%。

然后我这样做 n-1 次(n 是迭代的总数),所以你有余数。余数就是最后一个数,它本身并不是真正随机的,而是基于其他随机数。

效果很好。

/**
 * Calculate n random numbers that sum y.
 * Function calculates a percentage based on the number
 * required, gives a random number around that number, then
 * deducts the rest from the total for the final number.
 * Final number cannot be truely random, as it's a fixed total,
 * but it will appear random, as it's based on other random
 * values.
 * 
 * @author Mike Griffiths
 * @return Array
 */
private function _random_numbers_sum($num_numbers=3, $total=500)
{
    $numbers = [];

    $loose_pcc = $total / $num_numbers;

    for($i = 1; $i < $num_numbers; $i++) {
        // Random number +/- 10%
        $ten_pcc = $loose_pcc * 0.1;
        $rand_num = mt_rand( ($loose_pcc - $ten_pcc), ($loose_pcc + $ten_pcc) );

        $numbers[] = $rand_num;
    }

    // $numbers now contains 1 less number than it should do, sum 
    // all the numbers and use the difference as final number.
    $numbers_total = array_sum($numbers);

    $numbers[] = $total - $numbers_total;

    return $numbers;
}

这个:

$random = $this->_random_numbers_sum();
echo 'Total: '. array_sum($random) ."\n";
print_r($random);

输出:

Total: 500
Array
(
    [0] => 167
    [1] => 164
    [2] => 169
)

【讨论】:

    【解决方案2】:

    我发现这个问题的解决方案有点不同,但对我来说更有意义,所以在这个例子中,我生成了一个加起来为 960 的数字数组。希望这会有所帮助。

    // the range of the array 
    $arry = range(1, 999, 1);
    // howmany numbers do you want
    $nrresult = 3;
    do {
        //select three numbers from the array
        $arry_rand = array_rand ( $arry, $nrresult );
        $arry_fin = array_sum($arry_rand);
        // dont stop till they sum 960
    } while ( $arry_fin != 960 );
    
    //to see the results
    foreach ($arry_rand as $aryid) {
        echo $arryid . '+ ';
    }
    

    【讨论】:

      【解决方案3】:

      解决方案取决于您希望自己的值如何随机,换句话说,您要模拟什么样的随机情况。

      要获得完全随机分布,您必须进行 100 次民意调查,其中每个元素将以符号语言绑定到一个组

      foreach i from 1 to n
        group[ random(1,n) ] ++;
      

      对于更大的数字,您可以将所选组增加random(1, n/100) 或类似的值,直到总和与 n 匹配。

      但是,您想获得平衡,所以我认为最适合您的是正态分布。绘制 5 个高斯值,将数字(它们的总和)分成 5 部分。现在您需要缩放这些部分,使它们的总和为 n 并将它们四舍五入,这样您就得到了 5 个组。

      【讨论】:

        【解决方案4】:

        选择 4 个随机数,每个平均大约 20 个(分布例如大约 20 个的 40%,即 8 个)。添加第五个数字,使总数为 100。

        回应这里的其他几个答案,其实最后一个数不可能是随机的,因为总和是固定的。作为解释,在下图中,只有 4 个点(较小的刻度)可以随机选择,累积表示,每个点在所有点的平均值周围添加一个随机数(总计/n,20),总和为 100。结果是 5 个间距,代表您要查找的 5 个随机数。

        【讨论】:

        • @Sandro Antonucci:刚刚调整了我的解释,发现您的示例 20,3,34,15,18 加起来不等于 100。但这就是您的意思,对吗? (对我之前的回答投了反对票,想知道为什么)
        【解决方案5】:

        根据您需要的随机性以及您计划运行脚本的环境的资源丰富程度,您可以尝试以下方法。

        <?php
        set_time_limit(10);
        
        $number_of_groups   = 5;
        $sum_to             = 100;
        
        $groups             = array();
        $group              = 0;
        
        while(array_sum($groups) != $sum_to)
        {
            $groups[$group] = mt_rand(0, $sum_to/mt_rand(1,5));
        
            if(++$group == $number_of_groups)
            {
                $group  = 0;
            }
        }
        

        生成结果的例子,看起来像这样。很随意。

        [root@server ~]# php /var/www/dev/test.php
        array(5) {
          [0]=>
          int(11)
          [1]=>
          int(2)
          [2]=>
          int(13)
          [3]=>
          int(9)
          [4]=>
          int(65)
        }
        [root@server ~]# php /var/www/dev/test.php
        array(5) {
          [0]=>
          int(9)
          [1]=>
          int(29)
          [2]=>
          int(21)
          [3]=>
          int(27)
          [4]=>
          int(14)
        }
        [root@server ~]# php /var/www/dev/test.php
        array(5) {
          [0]=>
          int(18)
          [1]=>
          int(26)
          [2]=>
          int(2)
          [3]=>
          int(5)
          [4]=>
          int(49)
        }
        [root@server ~]# php /var/www/dev/test.php
        array(5) {
          [0]=>
          int(20)
          [1]=>
          int(25)
          [2]=>
          int(27)
          [3]=>
          int(26)
          [4]=>
          int(2)
        }
        [root@server ~]# php /var/www/dev/test.php
        array(5) {
          [0]=>
          int(9)
          [1]=>
          int(18)
          [2]=>
          int(56)
          [3]=>
          int(12)
          [4]=>
          int(5)
        }
        [root@server ~]# php /var/www/dev/test.php
        array(5) {
          [0]=>
          int(0)
          [1]=>
          int(50)
          [2]=>
          int(25)
          [3]=>
          int(17)
          [4]=>
          int(8)
        }
        [root@server ~]# php /var/www/dev/test.php
        array(5) {
          [0]=>
          int(17)
          [1]=>
          int(43)
          [2]=>
          int(20)
          [3]=>
          int(3)
          [4]=>
          int(17)
        }
        

        【讨论】:

        • 嗨,你能解释一下为什么在 if 条件中你放 $group = 0 吗?看不懂用法
        • 我想我明白了。找到一个最终的数字来达到总数,对吧?非常聪明:)
        【解决方案6】:

        这应该可以满足您的需要:

        <?php
        $tot = 100;
        $groups = 5;
        $numbers = array();
        for($i = 1; $i < $groups; $i++) {
            $num = rand(1, $tot-($groups-$i));
            $tot -= $num;
            $numbers[] = $num;
        }
        $numbers[] = $tot;
        

        不过,它不会给你一个真正平衡的分布,因为第一个数字平均会更大。

        【讨论】:

        • 我收到了Array ( [0] =&gt; 11 [1] =&gt; 48 [2] =&gt; 26 [3] =&gt; 7 [4] =&gt; 6 )。加起来是 98。
        • 糟糕,已修复。不过,最后一个数字不是随机的。
        • 如果你想“平衡分布”,你可以在末尾添加一个步骤来随机化数组索引。
        • 是的。在完成的数组上调用array_shuffle()平衡分布,但数字仍然不是真正随机的。
        【解决方案7】:
        $number = 100;
        $numbers = array();
        $iteration = 0;
        while($number > 0 && $iteration < 5) {
            $sub_number = rand(1,$number);
            if (in_array($sub_number, $numbers)) {
                continue;
            }
            $iteration++;
            $number -= $sub_number;
            $numbers[] = $sub_number;    
        } 
        
        if ($number != 0) {
            $numbers[] = $number;
        }
        
        print_r($numbers);
        

        【讨论】:

        • 这看起来不错,问题是如果一个数字很高,它会在数学上减少“组”总数,从而更快地达到总数。例如,如何告诉脚本“继续尝试”一个随机数,直到它低于 30?
        • if($sub_number &lt;= 30){ $iteration++; $number -= $sub_number; $numbers[] = $sub_number; } 添加这个有效,但最后一个数字可能会变得很大
        • 如果你的第一个数字是 95 或更高,它会爆炸。 95,1,2,?,?,?如果不允许重复,或 99,1,?,?,?如果是的话。
        【解决方案8】:

        我认为解决这个问题的诀窍是继续将随机生成器的上限设置为 100 - currentTotal

        【讨论】:

        • 这种方法不会给你一个特别平衡的分布(平均而言,第一个元素可能比后面的元素大得多)。但公平地说,OP 没有指定分布。
        猜你喜欢
        • 2013-03-02
        • 1970-01-01
        • 2014-01-23
        • 2015-09-22
        • 2021-09-28
        • 2012-04-17
        • 1970-01-01
        • 1970-01-01
        • 2021-12-08
        相关资源
        最近更新 更多