我很难解决这个简单的问题:我想创建一些随机的民意调查数字。我有4个变量需要填充数据(实际上是一个整数数组)。这些数字应代表随机百分比。所有百分比均为100%。听起来很简单。
但我认为这并不容易。我的第一次尝试是生成一个介于10和base(base = 100)之间的随机数,并减去基数中的数字。这样做了3次,最后一个值被分配了基数。有更优雅的方式吗?
我的问题用几句话说:
如何用随机值填充此数组,这些值在加在一起时将为100?
int values[4];
答案 0 :(得分:5)
您需要编写代码来模拟您正在模拟的内容。
因此,如果您有四个选择,则生成随机数的样本大小(0..1 * 4),然后将所有0,1,2和3加起来(记住4不会被选中)。然后将计数除以样本大小。
for (each sample) {
poll = random(choices);
survey[poll] += 1;
}
使用计算机模拟事物很容易,简单的模拟非常快。
请记住,您正在使用整数,并且整数不会很好地划分而不将它们转换为浮点数或双精度数。如果你错过了几个百分点,则可能与整数除以余数有关。
答案 1 :(得分:2)
你在这里遇到的问题是将数字100分成4个随机整数。这称为 partitioning in number theory
此问题已得到解决here。
在那里提出的解决方案基本上具有以下内容:
如果计算,n
时间内整数O(n^2)
有多少个分区。这会生成一个大小为O(n^2)
的表,然后可以在k
时间内为任何整数n
生成k
O(n)
分区n = 100
。
在您的情况下,k = 4
和 <!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Store</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<link href="index.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="navbar navbar-inverse navbar-static-top">
<div class="container">
<a href = "#" class ="navbar-brand">Site</a>
<button class="navbar-toggle" data-toggle="collapse" data-target = ".navHeaderCollapse">
Menu
</button>
<div class="collapse navbar-collapse navHeaderCollapse">
<ul class = "nav navbar-nav navbar-right">
<li><a href="#">Home</a></li>
</ul>
</div>
</div>
</div>
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
</body>
</html>
。
答案 2 :(得分:1)
在范围&lt; 0..1&gt;中生成x1,从1减去它,然后在范围&lt; 0..1-x1&gt;范围内生成x2。等等。最后一个值不应该是randomed,但在你的情况下等于1-x1-x2-x3。
答案 3 :(得分:1)
我认为这听起来并不像你已经做过的那么漂亮,但确实有效。 (唯一的好处是,如果你想要超过4个元素,它是可扩展的。)
确保#include <stdlib.h>
int prev_sum = 0, j = 0;
for(j = 0; j < 3; ++j)
{
values[j] = rand() % (100-prev_sum);
prev_sum += values[j];
}
values[3] = 100 - prev_sum;
答案 4 :(得分:1)
为随机分区提供真正无偏见的解决方案需要做一些工作。问题。但首先必须了解什么是“无偏见的”#34;在这种情况下意味着。
一种推理是基于随机抛硬币的直觉。一个没有偏见的硬币会像尾巴一样经常出现,因此我们可能会认为通过将无偏硬币投掷100次并计数,我们可以将100个投掷的无偏分区分为两个部分(头数和尾数)。 。这是Edwin Buck's proposal的本质,修改为生成四分区而不是两分区。
然而,我们发现的是许多分区永远不会出现。有101个两个分区100 - {0, 100}, {1, 99} … {100, 0}
但硬币采样解决方案在10,000次尝试中发现不到一半。正如所预料的那样,分区{50, 50}
是最常见的(7.8%),而从{0, 100}
到{39, 61}
的所有分区总共不到1.7%(并且在我做了一次试验,从{0, 100}
到{31, 69}
的分区根本没有出现。)[注1]
因此,它似乎不是可能分区的无偏见样本。无偏见的分区样本将以相同的概率返回每个分区。
另一个诱惑是从所有可能的大小中选择分区的第一部分的大小,然后从剩下的任何内容中选择第二部分的大小,依此类推,直到我们达到少于一个比分区的大小,在那一点上剩下的东西都在最后一部分。然而,这也会产生偏差,因为第一部分比任何其他部分都要大得多。
最后,我们可以枚举所有可能的分区,然后随机选择其中一个。这显然是公正的,但不幸的是,有很多可能的分区。例如,对于4分区为100的情况,有176,581种可能性。也许在这种情况下这是可行的,但它似乎不会导致一般的解决方案。
对于更好的算法,我们可以从观察分区开始
{p1, p2, p3, p4}
可以在没有偏见的情况下重写为累积分布函数(CDF):
{p1, p1+p2, p1+p2+p3, p1+p2+p3+p4}
其中最后一项只是所需的总和,在本例中为100。
这仍然是[0,100]范围内的四个整数的集合;但是,它保证会按顺序递增。
生成以100结尾的四个数字的随机排序序列并不容易,但生成三个不大于100的随机整数,排序它们,然后查找相邻差异是微不足道的。这导致了一个几乎无偏见的解决方案,这可能足以满足大多数实际目的,特别是因为实施几乎是微不足道的:
(Python)的
def random_partition(n, k):
d = sorted(randrange(n+1) for i in range(k-1))
return [b - a for a, b in zip([0] + d, d + [n])]
不幸的是,由于sort
,这仍然存在偏见。选择未排序列表时没有偏离可能列表的范围,但排序步骤不是简单的一对一匹配:具有重复元素的列表比没有重复元素的列表具有更少的排列,因此特定排序列表的概率没有重复的次数远远高于带有重复的排序列表的概率。
随着n相对于k变大,具有重复的列表的数量迅速下降。 (这些对应于其中一个或多个部分为0的最终分区。)在渐近线中,我们从连续体中选择并且碰撞具有概率0,该算法是无偏的。即使在n = 100,k = 4的情况下,对于许多实际应用,偏差也可能是可忽略的。将n增加到1000或10000(然后缩放生成的随机分区)可以减少偏差。
有快速算法可以产生无偏的整数分区,但它们通常难以理解或变慢。慢的,需要时间(n),类似于reservoir sampling;要获得更快的算法,请参阅Jeffrey Vitter.
的工作以下是快速而肮脏的Python + shell测试:
$ python -c '
from random import randrange
n = 2
for i in range(10000):
d = n * [0]
for j in range(100):
d[randrange(n)] += 1
print(' '.join(str(f) for f in d))
' | sort -n | uniq -c
1 32 68
2 34 66
5 35 65
15 36 64
45 37 63
40 38 62
66 39 61
110 40 60
154 41 59
219 42 58
309 43 57
385 44 56
462 45 55
610 46 54
648 47 53
717 48 52
749 49 51
779 50 50
788 51 49
723 52 48
695 53 47
591 54 46
498 55 45
366 56 44
318 57 43
234 58 42
174 59 41
118 60 40
66 61 39
45 62 38
22 63 37
21 64 36
15 65 35
2 66 34
4 67 33
2 68 32
1 70 30
1 71 29
答案 5 :(得分:-2)
你可以强制它,创建一个计算功能,将数字中的数字相加。如果它们不等于100,则重新生成数组中的随机值,再次进行计算。