我正在努力解决我无法解决的随机化算法。
以下是随机化标准。
- 用户输入一个随机整数,即 28
- 用户输入一个系数,即 1.2
- 如果用户在#1点输入28,在#2点输入1.2,那么总共应该生成28个随机数,这28个随机数的总和必须等于29.2
- 每个随机数必须是 0.01 到 9.99 之间的值,最多两位小数。
我已经完成了我的代码,它符合条件 1-3,但我似乎无法满足条件 4。如果预先生成大量高随机数,则结束迭代将不足以生成至少 0.01。它始终为 0.00。我错过了什么吗?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RandomizeAlgo
{
public static class Extend
{
public static double RandomNumberBetween(this Random random, double minValue, double maxValue)
{
var next = random.NextDouble();
return minValue + (next * (maxValue - minValue));
}
public static double ToFloor(this double value)
{
return Math.Floor(value * 100) / 100;
}
}
class Program
{
static void Main(string[] args)
{
var rnd = new Random();
var totalPeople = 28;
var factor = 1.2;
var shouldHaveTotalNumber = totalPeople + factor;
var defaultMin = 0.01;
var defaultMax = 9.99;
while (true)
{
var iteration = 0;
var balance = shouldHaveTotalNumber;
var listOfRandomizedNumber = new List<double>();
for (var i = 1; i <= totalPeople; i++)
{
var randomizeResult = 0.00;
if (i == totalPeople)
{
randomizeResult = balance;
}
else if (balance >= defaultMax)
{
randomizeResult = rnd.RandomNumberBetween(defaultMin, defaultMax);
randomizeResult = randomizeResult.ToFloor();
}
else
{
randomizeResult = rnd.RandomNumberBetween(defaultMin, balance);
randomizeResult = randomizeResult.ToFloor();
}
listOfRandomizedNumber.Add(randomizeResult);
Console.WriteLine(string.Format("{0:0.00}", randomizeResult));
balance = balance - randomizeResult;
}
iteration++;
//Assertion
var totalSumNumberGenerated = listOfRandomizedNumber.Sum().ToString("0.00");
if (totalSumNumberGenerated != shouldHaveTotalNumber.ToString("0.00"))
{
throw new InvalidOperationException("Total #"+ iteration + " iteration is: " + totalSumNumberGenerated + " . Invalid Randomize Number. Sum does not match");
}
else
{
Console.WriteLine("Iteration #"+ iteration + " successfully generated");
}
}
}
}
}
最佳答案
随机化总和的比例,而不是大小
既然您似乎不关心分发,那么采用不同的方法如何?生成任意范围内的随机数列表,计算它们的总和,然后计算将总和缩放到目标的常数。例如,如果实际总和为 10,但目标总和为 20,则缩放值为 2。然后将每个元素乘以 2。
另一种看待它的方式是,您正在生成一系列数字,这些数字表示元素对总和的贡献比例,而不是幅度本身。
这种方法总是会在一次迭代中获得您需要的列表,除了一件讨厌的事情:您的范围和精度要求。通过将精度强制为小数点后两位,我们可以将自己四舍五入到目标之外,因此我们需要仔细检查,然后迭代几次,直到结果出来。
此外,不要忘记 floating point comparisons must use a tolerance ,在本例中为 0.005。
public static List<double> GetTheList(int count, double target)
{
var random = new Random();
var iteration = 0;
while (true)
{
iteration++;
//Start with a list of random numbers of any range
var list = Enumerable.Range(1, count).Select( i => random.NextDouble() );
//Take the sum
var sum = list.Sum();
//Determine a scaling factor to make the sum hit the target
var scale = target / sum;
//Scale all of the numbers, and round them off
var results = list.Select( n => Math.Round(n * scale, 2) ).ToList();
//Check to see if rounding errors put you off target
if (Math.Abs(results.Sum() - target) > 0.005) continue;
//Ensure bounds
if (results.Min() < 0.01 || results.Max() > 99.9) continue;
//The list matches all the criteria, so return it
Console.WriteLine("{0} iterations executed.", iteration);
return results;
}
}
关于c# - 如何根据 C# 中的标准随机化数字?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52903187/