c# - 如何根据 C# 中的标准随机化数字?

标签 c# .net algorithm random

我正在努力解决我无法解决的随机化算法。

以下是随机化标准。

  1. 用户输入一个随机整数,即 28
  2. 用户输入一个系数,即 1.2
  3. 如果用户在#1点输入28,在#2点输入1.2,那么总共应该生成28个随机数,这28个随机数的总和必须等于29.2
  4. 每个随机数必须是 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;
    }
}

Example on DotNetFiddle

关于c# - 如何根据 C# 中的标准随机化数字?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52903187/

相关文章:

python - 解码附加数的标准解决方案

c# - 如何围绕数据库中的空值设计类?

c# - 我应该返回一个空列表还是一个空列表?

algorithm - 找到非固定长度 x 的每个子数组的最小值的最大值,其中 1<= x <= N

c# - 仅具有管理员权限的 Windows Vista 中的浏览器帮助程序对象 (BHO)?

c# - LINQ Max() 函数执行速度超慢

algorithm - 使用强连接组件进行拓扑排序以查找循环(​​有向图)

c# - IFormFile 的 POST 没有使其生效

c# - C# 的 DataSet WriteXML 转换的奇怪结果

c# - 为什么 decimal 不是原始类型?