简体   繁体   English

如何生成总和为预定值的 N 个随机值?

[英]How can I generate N random values that sum to predetermined value?

I need your help with a little problem.我需要你的帮助来解决一个小问题。 I have four labels and I want to display on them random value between 0 to 100, and the sum of them must be 100.我有四个标签,我想在它们上显示 0 到 100 之间的随机值,它们的总和必须是 100。

This is my code:这是我的代码:

private void randomly_Click(object sender, EventArgs e)
{
    double alpha = 0, beta = 0, gamma = 0, delta = 0;
    double temp;
    int tempDouble;

    Random rnd = new Random();

    alpha = rnd.Next(0, 100);

    temp = 100 - alpha;
    tempDouble = (int)temp;
    beta = rnd.Next(0, tempDouble);

    temp = 100 - (alpha + beta);
    tempDouble = (int)temp;
    gamma = rnd.Next(0, tempDouble);

    temp = 100 - (alpha + beta + gamma);
    tempDouble = (int)temp;
    delta = rnd.Next(0, tempDouble);

    temp = alpha + beta + delta + gamma;
    temp = 100 - temp;
    temp = temp / 4;

    alpha = alpha + temp;
    beta = beta + temp;
    gamma = gamma + temp;
    delta = delta + temp;

    cInsertion.Text = alpha.ToString();
    cMoyens.Text = beta.ToString();
    cInternational.Text = gamma.ToString();
    cRecherche.Text = delta.ToString();
}   

The problem is that I'm giving to the alpha the chance to have the biggest value, and for delta the lowest value.问题是我让 alpha 有机会获得biggest价值,而 delta 则获得lowest价值。

Is there any way to give them all the same chance to have a real random value?有没有办法让他们都有相同的机会获得真正的random值?

You could do something like this:你可以这样做:

double alpha = 0, beta = 0, gamma = 0, delta = 0, k = 0;
Random rnd = new Random();

alpha = rnd.Next(0, 100);
beta = rnd.Next(0, 100);
gamma = rnd.Next(0, 100);
delta = rnd.Next(0, 100);

k = (alpha + beta + gamma + delta) / 100;

alpha /= k;
beta /= k;
gamma /= k;
delta /= k;

cInsertion.Text = alpha.ToString();
cMoyens.Text = beta.ToString();
cInternational.Text = gamma.ToString();
cRecherche.Text = delta.ToString();

This way you're saying let's take a random value for all 4 variables, and then we'll scale them by a factor k that'll make their sum be 100.这样你的意思是让我们为所有 4 个变量取一个随机值,然后我们将它们按因子k缩放,使它们的总和为 100。

What if you stick all four values in an array, then shuffle them , then assign them according to their ordinal position?如果您将所有四个值都放在一个数组中,然后将它们 洗牌,然后根据它们的序数 position 分配它们会怎样? That way each variable (gamma, theta, etc.) has equal probability of getting a high vs low number.这样,每个变量(伽马、θ 等)都有相同的概率获得高数和低数。

It's a very interesting problem.这是一个非常有趣的问题。 I like @Ivan_Ferić's solution, I think, it's perfect, but I have another idea:我喜欢@Ivan_Ferić 的解决方案,我认为它很完美,但我有另一个想法:

int total = 100;
Random rand = new Random();

int half = rand.next(0,total);   // the line

a = rand.Next(0,half);
b = max - a;
c = rand.Next(0,half);
d = max - c;

(Not tested, maybe +/-1 must be added to some of vars.) Also, you may shuffle values. (未经测试,可能必须将 +/-1 添加到某些变量中。)此外,您可以随机播放值。

The interesting part is coming now.有趣的部分现在来了。 If we change "the line":如果我们改变“线”:

min = <some_value>
max = <another_value>;
int half = rand.next(min,max);

...then we can finetune the result: ...然后我们可以微调结果:

  • min = 0;最小值 = 0; max = 100: original;最大值 = 100:原始;
  • min = 20;最小值 = 20; max = 80: avoid little numbers; max = 80:避免小数字;
  • min = 33;最小值 = 33; max = 100: force two numbers to be less than 32. max = 100:强制两个数字小于 32。

Instead of generating the individual numbers randomly, generate the partial sums, then calculate the parts:不是随机生成单个数字,而是生成部分和,然后计算部分:

double alpha, beta, gama, delta = 0;

var rnd = new System.Random();
var cuts = new List<double>();

cuts.Add(Math.Floor(rnd.Next(0, 101)));
cuts.Add(Math.Floor(rnd.Next(0, 101)));
cuts.Add(Math.Floor(rnd.Next(0, 101)));

cuts.Sort();

alpha = cuts[0];
beta = cuts[1] - cuts[0];
gamma = cuts[2] - cuts[1];
delta = 100 - cuts[2];

If the numbers that you want represent probabilities of mutually exclusive outcomes, you can imagine them as a multinomial distribution.如果您想要的数字代表互斥结果的概率,您可以将它们想象为多项分布。 Since you want a random probability vector, you should sample that from the conjugate prior of the multinomial distribution: the Dirichlet distribution.由于您需要一个随机概率向量,因此您应该从多项分布的共轭先验中对其进行采样:Dirichlet 分布。

In code, you just what Ivan suggested, except that alpha, beta, gamma, and delta should all be drawn from Gamma distributions with shape paramaters alpha_shape, beta_shape, gamma_shape, and delta_shape respective.在代码中,您正是 Ivan 所建议的,除了 alpha、beta、gamma 和 delta 都应该从具有形状参数 alpha_shape、beta_shape、gamma_shape 和 delta_shape 的 Gamma 分布中绘制。 (Let the other parameter of the Gamma distribution be 1.) These shape parameters control the expected relative proportions. (让 Gamma 分布的其他参数为 1。)这些形状参数控制预期的相对比例。

A real random number? 一个 真正的随机数? In short, no. 简而言之,没有。 Only a pseudo-random number. 只有一个伪随机数。

The random number generator operates off clock cycles and it is typical to see repeated sequences. 随机数生成器在时钟周期之外运行,并且通常会看到重复的序列。 The seed used depends on the.Tick property of the current DateTime.Now ( if I remember correctly ). 使用的种子取决于当前 DateTime.Now 的 .Tick 属性( 如果我没记错的话)。 There are a lot of decent random number generators and APIs for.Net.I would recommend searching for those if you feel like you don't have the time or desire to put into rolling your own. 有很多不错的随机数生成器和用于 .Net 的 API。如果您觉得自己没有时间或不想自己动手,我建议您搜索它们。

Moved up to comments as it seems more appropriate.移至评论,因为它似乎更合适。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM