具有固定平均值的随机数

我想在1到10之间生成100个随机数。但是这100个随机数的平均值应该是7.我怎么能这样做? 我这样做:

//generating random number Random random = new Random(); int value = random.Next(1,10); 

并将每个值存储在一个数组中。 如果数组中100个项目的平均值不是7,那么我需要再获得100个随机数。 谁能建议更好的方法呢?

  1. A[0], ..., A[99]初始化为1
  2. 初始化I = {0, 1, ..., 99}
  3. 重复步骤4-6 600次。
  4. I统一随机选择i
  5. 增加A[i]
  6. 如果A[i] == 10 ,那么从I删除i

这将保证sum(A)为700,因此avg(A)为7。

但请注意,这并不能在{1,…,10}中的所有100个整数数组上进行均匀分布,使得它们总和为700.设计一个算法进行均匀采样将是一项更具挑战性的练习。

 public int RandomNumberThatAveragesToSeven() { //Chosen by fair dice roll //Guaranteed to be random return 7; } 

没有附加参数,上述算法满足每个要求。

  1. 返回必须在1到10之间
  2. 当n倾向于inf时,多次调用的平均值必须趋于7。

编辑因为这个答案有很多争议……我添加了这个答案……这绝对是随机的。

 public List ProduceRandom100NumbersWithAverageOfSeven() { var rand = new Random(); var seed = rand.Next(); if(seed > 0.5) { return new List(Enumerable.Concat( Enumerable.Repeat(6, 50), Enumerable.Repeat(8, 50))); } else { return new List(Enumerable.Concat( Enumerable.Repeat(8, 50), Enumerable.Repeat(6, 50))); } } 

此函数用于随机获取n个记录之间的固定平均值。 在我的答案中,“n”被声明为“count”。 https://github.com/amingolmahalle/RandomGenerateDataBetweenTwoNumber

 public void ProccessGenerateData(WorkBook workBookData, out List nomreList, out int adjustmentsVal) { try { nomreList = new List(); adjustmentsVal = 0; int count = workBookData.NumberStudents; double min = workBookData.Min; double max = workBookData.Max; double target = workBookData.FixedAvg; double tolerance = workBookData.Tolerance; double minAverage = Math.Round(target - tolerance, 2); double maxAverage = Math.Round(target + tolerance, 2); Random r = new Random(DateTime.Now.Millisecond); List listNomre = new List(); double sum = 0; for (int i = 0; i < count; i++) { double d = Math.Round(RangedDouble(min, max, r), 2); listNomre.Add(d); sum += d; sum = Math.Round(sum, 2); } int adjustments = 0; while (Math.Round((sum / count), 2) < minAverage || Math.Round((sum / count), 2) > maxAverage) { if (Math.Round((sum / count), 2) < minAverage) { double oldDbl1 = listNomre.First(d => d < minAverage); //min a1 is oldDbl1 , x1 --> Unknown double newDbl1 = Math.Round(oldDbl1 + RangedDouble(min-oldDbl1, max - oldDbl1, r), 2); listNomre.Remove(oldDbl1); sum -= oldDbl1; sum = Math.Round(sum, 2); listNomre.Add(newDbl1); sum += newDbl1; sum = Math.Round(sum, 2); adjustments++; continue; } double oldDbl = listNomre.First(d => d > maxAverage); //min a1 is oldDbl , x1 --> Unknown double newDbl = Math.Round(oldDbl - RangedDouble(oldDbl-max, oldDbl - min, r), 2); listNomre.Remove(oldDbl); sum -= oldDbl; sum = Math.Round(sum, 2); listNomre.Add(newDbl); sum += newDbl; sum = Math.Round(sum, 2); adjustments++; } nomreList = listNomre; adjustmentsVal = adjustments; } catch (Exception ex) { MessageBox.Show(ex.Message); throw; } } private static double RangedDouble(double min, double max, Random r) { //Function RangedDouble => Random Number Between 2 Double Numbers //Random.NextDouble => returns a double between 0 and 1 return Math.Round( r.NextDouble() * (max - min) + min,2); } 

这样的事情可能会这样:

 public static void Main(string[] args) { var randomList = new List(); var random = new Random(); var avg = 0; while (avg != 7) { randomList = new List(); GenerateList(randomList, random); avg = (int) randomList.Average(); } for (var i = 0; i < randomList.Count; i++) { Console.WriteLine(string.Format("Index: {0}, Number: {1}", i, randomList.ElementAt(i))); } } private static void GenerateList(List refList, Random random) { for (var i = 0; i < 100; i++) { refList.Add(random.Next(1, 10)); } } 

我的2美分

 using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Stopwatch watch = Stopwatch.StartNew(); int count = 100; Double min = 0; Double max = 10; Double target = 7; Double tolerance = 0.00000001; Double minAverage = target - tolerance; Double maxAverage = target + tolerance; Random r = new Random(); List numbers = new List(); Double sum = 0; for (int i = 0; i < count; i++) { Double d = RangedDouble(min, max, r); numbers.Add(d); sum += d; } int Adjustments = 0; while((sum / count < minAverage || (sum / count) > maxAverage)) { while ((sum / count) < minAverage) { Double oldDbl = numbers.First(d => d < minAverage); Double newDbl = oldDbl + RangedDouble(minAverage - oldDbl, 10 - oldDbl, r); numbers.Remove(oldDbl); sum -= oldDbl; numbers.Add(newDbl); sum += newDbl; Adjustments++; } while ((sum / count) > maxAverage) { Double oldDbl = numbers.First(d => d > maxAverage); Double newDbl = oldDbl - RangedDouble(oldDbl - maxAverage, oldDbl, r); numbers.Remove(oldDbl); sum -= oldDbl; numbers.Add(newDbl); sum += newDbl; Adjustments++; } } watch.Stop(); int x = 0; while (x < count) { Console.WriteLine("{0:F7} {1:F7} {2:F7} {3:F7}", numbers.Skip(x).Take(1).First(), numbers.Skip(x + 1).Take(1).First(), numbers.Skip(x + 2).Take(1).First(), numbers.Skip(x + 3).Take(1).First()); x += 4; } Console.WriteLine(); Console.WriteLine(watch.ElapsedMilliseconds); Console.WriteLine(numbers.Average()); Console.WriteLine(Adjustments); Console.ReadKey(true); } private static double RangedDouble(Double min, Double max, Random r) { return (r.NextDouble() * (max - min) + min); } } } 

并输出:

8.1510368 7.2103030 7.9909210 9.6693311
8.2275382 7.2839244 8.8634567 7.9751014
7.8643791 7.2262462 9.8914455 9.6875690
8.4396683 8.4308401 7.5380218 8.6147181
8.2760663 7.7399011 7.4312152 9.2115622
9.7850111 9.1061378 9.8672965 9.5610411
7.0415607 8.8446195 9.3562218 8.5279759
7.5227340 9.3572417 9.8927997 9.5880645
9.0908564 7.0918394 9.6213258 8.6528169
9.3803283 9.6869223 1.4006790 3.3310691
7.0719214 2.6370854 9.7558776 8.9180391
3.0486700 5.0082988 8.8624504 5.0497899
0.9692377 7.7140550 9.8495115 6.4933865
4.4939760 9.3187625 5.4353003 6.5405668
9.5693118 5.0339998 6.9644440 4.6902072
0.5241568 9.7748420 0.1406617 8.4731427
9.8064604 6.3113773 0.8628048 9.2417028
8.9148867 9.3111336 3.2424080 9.6710544
4.3794982 5.1687718 9.8207783 0.3283217
9.8321869 2.8093698 7.4377070 4.1130959
5.9840738 9.2560763 3.6691865 2.5498863
7.3242246 7.0179332 5.8906831 9.3340545
0.3735044 7.2442886 0.4409532 9.0749754
9.6716409 8.4097246 2.8069123 7.2970794
2.4964238 8.2826350 9.1115787 3.7373927

1
6.99992266645471
729

编辑 :更改代码以始终导致平均精确7。

这基本上是您已经在做的优化版本。 在进行检查之前,它只生成10个而不是生成另外100个数字。

 using System.Collections.Generic; using System.Linq; 

 var r = new Random(); var numbers = new List(); while (numbers.Count < 100) { var stack = new Stack(); for (int i = 0; i < 10; i++) { stack.Push(r.Next(10)); } if (stack.Sum() == 70) { numbers.AddRange(stack); } } Console.WriteLine(numbers.Average()); 

好吧,做那样的事情可能会很棘手。

如果您需要获得100个不同的数字,并且您需要它们的平均值为7,那么您需要它们总和700。

您需要跟踪每个数字及其总和。 虽然700减去您到目前为止获得的值的总和小于10 *您尚未获得的数字量,但您可以继续获得纯随机值。

当您获得的值总和小于您需要获得的值时,您将最后一个数字改为10,将剩余数字中的10个更改为列表末尾所需的数字,最后一个数字数字,你得到700和99之前的伪随机值的总和之间的差异。

随机播放你的arrays和音乐 ,你有一个100个伪随机数组,数字从1到10,平均值为7.当然它会比你想要的多10个,但你肯定能够微调这个“算法“使它更容易发生。

嗯,等一下,如果你得到平均值超过7的随机值怎么办? 您还需要跟踪当前值的总和小于您尚未获得的数字。 如果您在任何时候超过此值,您需要将您的最后一个数字转换为1,在剩余的所需值上加1,并再次获得最后一个数字作为700和99之前值之间的差值。

就像其他答案一样,由于我们知道长度,我们只需关注总和即可得到平均值。

我会递归地解决它。 在基本情况下,我们需要生成长度为1的列表,该列表总和为某个数字s 。 这很简单:列表只包含s

 rand 1 s = [s] 

现在我们可以解决递归情况rand ns ,其中n是所需的列表长度, s是所需的总和。 为此,我们将生成两个列表xy ,并根据给定的约束将它们连接在一起:

 length x + length y = n sum x + sum y = s 1 * length x <= sum x -- Minimum value is 1 10 * length x >= sum x -- Maximum value is 10 1 * length y <= sum y 10 * length y >= sum y 

这些方程/不等式还不能解决,所以我们要做的第一件事就是选择列表的长度。 为了降低递归水平,我们可以选择lx = round (n / 2)然后设置以下内容:

 length x = lx length y = n - lx = ly 

因此:

 sum x + sum y = s 1 * lx <= sum x 10 * lx >= sum x 1 * ly <= sum y 10 * ly >= sum y 

我们使用第一个方程来重写不等式:

 1 * lx <= sum x 10 * lx >= sum x 1 * ly <= s - sum x 10 * ly >= s - sum x 

我们可以重新排列底部两个以使得sum x成为主题:

 sum x + 1 * ly <= s sum x + 10 * ly >= s sum x <= s - 1 * ly sum x >= s - 10 * ly 

我们知道它们,因此这些给出了sum x明确界限,我们通过取最大下界和最小上界来组合:

 max (1 * lx) (s - 10 * ly) <= sum x min (10 * lx) (s - 1 * ly) >= sum x 

这些界限是有意义的:它们考虑了x中的每个元素都是1或10的情况, 并且它们确保余数可以用sum y来处理。 现在我们只是在这些边界之间生成一个随机数B ,然后设置:

 sum x = B sum y = s - B 

从那里,我们可以执行递归(假设一些随机数函数randInt ):

 rand ns = let lx = round (n / 2) ly = n - lx lower = max (1 * lx) (s - 10 * ly) upper = min (10 * lx) (s - 1 * ly) b = randInt lower upper in rand lx b ++ rand ly (s - b) 

现在您的列表可以通过调用生成:

 myList = rand 100 700 

为简洁起见,我在Haskell中编写了这个,但它只是算术,所以应该很容易转换为C#。 如果它有帮助,这是一个Python版本:

 def rand(n, s): if n == 1: return [s] lx = int(n / 2) ly = n - lx lower = max(1 * lx, s - 10 * ly) upper = min(10 * lx, s - 1 * ly) b = randint(lower, upper) result = rand(lx, b) result.extend(rand(ly, s - b)) return result 

请指出我犯过的任何错误!

编辑:虽然我怀疑C#的情况,但在某些语言中我们可以通过使用尾递归来使这更简单,更有效。 首先,我们切换到一次生成一个元素:

 -- Generate one number then recurse rand 1 s = [s] rand ns = let ly = n - 1 lower = max 1 (s - 10 * ly) upper = min 10 (s - 1 * ly) x = randInt lower upper in x : rand (n - 1) s 

然后我们累积结果而不是建立未完成的延续:

 rand' xs 1 s = s:xs rand' xs ns = let ly = n - 1 lower = max 1 (s - 10 * ly) upper = min 10 (s - 1 * ly) x = randInt lower upper in rand' (x:xs) (n-1) s rand = rand' [] 

这个方法生成一个随机数序列,然后继续加/减,直到我们得到正确的总数(700),只要我们改变的数字仍然在1-10的范围内

 List randomNumbers = new List(); for (int i = 0; i < 100; i++) { numbers.Add(r.Next(1, 10)); } int total = randomNumbers.Sum(); // Now fiddle until we get the correct total (700) if (total < 700) { while (total < 700) { for (int i = 0; i < 100; i++) { if (numbers[i] < 10) { numbers[i]++; total = randomNumbers.Sum(); if (total == 700) break; } } } } else if (total > 700) { while (total > 700) { for (int i = 99; i >= 0; i--) { if (numbers[i] > 0) { numbers[i]--; total = randomNumbers.Sum(); if (total == 700) break; } } } }