如何在C#中生成两个固定和的数字之间的随机数字序列?

如何在C#中生成两个固定和的数字之间的随机数字序列?,c#,math,random,numbers,C#,Math,Random,Numbers,所以我试图生成一个N个数的序列,其中的和是S 现在,我正在这样做: float baseamount = (float)(amount / norders) * 0.8f; float secondamount = amount / norders; 然后在这两个数字之间生成N个随机数 但是,这会生成一个相当统一的数字范围,而我希望更随机一些,例如,而不是(sum=200,n=10): 16.92321 17.49378 16.26426 16.03404 16.12497 17.53131

所以我试图生成一个N个数的序列,其中的和是S

现在,我正在这样做:

float baseamount = (float)(amount / norders) * 0.8f;
float secondamount = amount / norders;
然后在这两个数字之间生成N个随机数

但是,这会生成一个相当统一的数字范围,而我希望更随机一些,例如,而不是(sum=200,n=10):

16.92321 17.49378 16.26426 16.03404 16.12497 17.53131 18.10094 16.86982 17.0831 16.06921

我更喜欢:

12.345 17.4534 19.3542342 11.345345 18.4325235 14.4353245

最好的方法是什么?

生成(n-1)个不大于sum/n的随机数,并跟踪部分和(我们称之为PS)。 那么,您的最后一个数字是(sum-PS)

希望这有帮助

编辑:当然,最后一个数字比之前所有的数字都要大。我将研究这个问题的一个更加数学化的解决方案(或者至少我会尝试)。与此同时,我想到了一个“解决办法”:

(我们把随机序列称为a0,…,an)

  • 如上所述生成序列
  • 在间隔[0;k]内生成一个随机数
    rd
    (您需要选择k)
  • an-=rd
  • 对于每个
    ai
    ai+=rd/(n-1)

  • 如果我把每件事都做得很好,那么总数就不会改变,你就有了一个更统一的序列。k必须由您根据您希望序列的“一致性”程度来选择。

    此方法创建的n个值的平均值为
    总和/计数
    随定义的值而变化。在每个循环中,
    min
    max
    的常量计算可实现最后一个值(在本例中,它实际上是数组的第一个值)不太突出。尽管如此,它仍然不是完美的,特别是当你有一个小的平均值和一个大的方差。但也许这会给你一个开始

    public static IEnumerable<double> GetValues(int count, double sum, double variance)
        {
            var rnd = new Random();
            var values = new double[count];
    
            var remainingSum = sum;
            for (int i = count-1; i > 0; i--)
            {
                var min = (int)(remainingSum / (i+1) - variance / 2) * 1000;
                var max = (int)(remainingSum / (i+1) + variance / 2) * 1000;
    
                var rndVal = rnd.Next(min, max) / 1000.0;
                values[i] = rndVal;
                remainingSum -= rndVal; 
            }
            values[0] = remainingSum;
    
            return values;
        }
    
    公共静态IEnumerable GetValues(整数计数、双和、双方差)
    {
    var rnd=新随机数();
    var值=新的双[计数];
    var剩余金额=总和;
    对于(int i=count-1;i>0;i--)
    {
    var最小值=(整数)(剩余总和/(i+1)-方差/2)*1000;
    var max=(int)(剩余总和/(i+1)+方差/2)*1000;
    var rndVal=下一个(最小值、最大值)/1000.0;
    值[i]=rndVal;
    剩余金额-=rndVal;
    }
    值[0]=剩余和;
    返回值;
    }
    
    静态随机=新随机();
    浮点[]生成(浮点和,整数n,浮点最小限制)
    {
    浮点最大值=总和-最小极限*n;
    浮动[]arr=新浮动[n];
    对于(int i=0;i0;i--)
    {
    arr[i]=arr[i]-arr[i-1]+minLimit;
    }
    arr[0]+=minLimit;
    返回arr;
    }
    
    你看过这篇文章了吗?现在看看吧,因为这些数字是相关的,你不能用一些独立的随机变量来解决这个问题。你认识到这是不可能的吗?如果总和=200,n=10,则每个数字的平均值为20。因此,随机抽样将产生一些高于20的数字,一些低于20的数字,以使总和保持在200。根据您的要求,您希望数字明确地以20为单位,因此所有数字都将小于20,并且不可能将总和设置为200。即使在您的示例中,总和也远远超过200,使用多个随机实例也不是一个好主意。如果同时创建它们,则Next()的结果将是相同的。测试:
    for(inti=0;i<9;i++){Console.WriteLine(new Random().Next());}
    static Random random = new Random();
    
    float[] Generate(float sum, int n, float minLimit)
    {
        float max = sum - minLimit * n;
        float[] arr = new float[n];
        for (int i = 0; i < n - 1; i++)
        {
            arr[i] = (float)random.NextDouble() * max;
        }
        arr[n - 1] = max;
        Array.Sort(arr);
        for (int i = n - 1; i > 0; i--)
        {
            arr[i] = arr[i] - arr[i - 1] + minLimit;
        }
        arr[0] += minLimit;
        return arr;
    }