如何生成三个随机数,其总和为1?

时间:2011-04-06 08:57:16

标签: c# random distribution uniform

我需要生成3个随机数,其数量等于1。

我的实施不支持统一分发。 :(

9 个答案:

答案 0 :(得分:23)

只需获得3个随机数,然后计算一个因子,即1 / [数字之和]。最后将每个随机数乘以该因子。总和将是1。

答案 1 :(得分:9)

这实际上是一个棘手的问题。首先:
Daren 的解决方案并不统一,因为它不支持两个数字> 1/3。
Simen 的解决方案并不统一,假设“选择一个随机数”来自均匀分布,但这有点微妙。它至少在变量之间是对称的(即[a,b,c]的概率与其中任何排列的概率相同),但它更倾向于更接近(1/3,1 / 3,1 /)的解。 3)。通过观察极端情况来考虑这种方式: (1 / 3,1 / 3,1 / 3)可能来自任何(a,a,a),其范围从0到1。 (1,0,0),同样有效的三元组,必须来自(1,0,0)。

一个解决方案:添加到1的正数集在三维空间中形成等边三角形,坐标为(1,0,0),(0,1,0),( 0,0,1)。将其扩展为平行四边形 - 例如通过添加点(1,1,-1)作为第四点。这个双倍的区域 - 将第二个区域映射到第一个区域,这样就足以在这个平行四边形中选择一个随机点。

平行四边形可以通过(0,0,1)+ A(1,0,-1)+ B(0,1,-1)均匀采样,其中A和B均匀地从0到1。 / p>

-A

答案 2 :(得分:3)

生成0到1之间的两个随机数。 将每个人除以3。 第三个是1和两个随机三分之一的差异:

void Main()
{
    Random r = new Random();
    double d1 = r.NextDouble() / 3.0;
    double d2 = r.NextDouble() / 3.0;
    double d3 = 1.0 - d1 - d2;
    System.Console.WriteLine(d1);
    System.Console.WriteLine(d2);
    System.Console.WriteLine(d3);
    System.Console.WriteLine(d1 + d2 + d3);
}

这将在LINQPad中输出以下内容:

0.0514050276878934
0.156857372489847
0.79173759982226
1

答案 3 :(得分:1)

Marnix的回答略有不同:

  1. 从[0,1]
  2. 生成随机数a
  3. 生成两个随机数。来自[0,a]的x和来自[a,1]
  4. y
  5. 将结果设置为xy-x1-y

答案 4 :(得分:1)

有一种简单的方法可以做到这一点,但你需要能够生成一个统一的随机数。

让X在(0,2 / 3)上均匀。如果X < 1/3,设Y = X + 1/3。否则让Y = X - 1/3。设Z = 1 - X - Y.

在此设置下,X,Y和Z将总和为1,它们将具有相同的均匀(0,2 / 3)边际分布,并且所有三个成对相关将为 - (1/2)。

答案 5 :(得分:0)

<强>更新

  1. 创建一个包含3个随机数的vector3
  2. 规范化向量

答案 6 :(得分:0)

2/2方法:

  • 创建0到1的随机数列表;缩小到总数
  • 将列表小到大
  • 通过测量每个元素之间的空间来创建一个新列表 第一个清单
  • 舍入新列表中的每个元素
  • 将第一个元素替换为浮点帐户

抱歉,我不知道C#这是python中的样子:

import random
import time

PARTS       = 5
TOTAL       = 10
PLACES      = 3

def random_sum_split(parts, total, places):


    a = [0.0, total]
    for i in range(parts-1):
        a.append(random.random()*total)
    a.sort()
    b = []
    for i in range(1,(parts+1)):
        b.append(a[i] - a[i-1])
    if places != None:    
        b = [round(x, places) for x in b]  
    c = b[-(parts-1):]
    d = total - sum(c)
    if places != None:
        d = round(d, places)
    c.insert(0, d)

    log(a)
    log(b)
    log(c)
    log(d)

    return c

def tick():

    if info.tick == 1:

        start = time.time()

        alpha = random_sum_split(PARTS, TOTAL, PLACES)

        log('********************')
        log('***** RESULTS ******')
        log('alpha: %s' % alpha)
        log('total: %.7f' % sum(alpha))
        log('parts: %s' % PARTS)
        log('places: %s' % PLACES)

        end = time.time()  

        log('elapsed: %.7f' % (end-start))

收率:

Waiting...
Saved successfully.
[2014-06-13 00:01:00] [0.0, 1.3005056784596913, 3.0412441135728474, 5.218388755020509, 7.156425483589107, 10]
[2014-06-13 00:01:00] [1.301, 1.741, 2.177, 1.938, 2.844]
[2014-06-13 00:01:00] [1.3, 1.741, 2.177, 1.938, 2.844]
[2014-06-13 00:01:00] 1.3
[2014-06-13 00:01:00] ********************
[2014-06-13 00:01:00] ***** RESULTS ******
[2014-06-13 00:01:00] alpha: [1.3, 1.741, 2.177, 1.938, 2.844]
[2014-06-13 00:01:00] total: 10.0000000
[2014-06-13 00:01:00] parts: 5
[2014-06-13 00:01:00] places: 3
[2014-06-13 00:01:00] elapsed: 0.0036860

答案 7 :(得分:0)

1/2方法:

  • 创建一个随机数列表,每个0到1的长度为PARTS。
  • 总结清单
  • 将每个元素除以总和
  • 围绕每个元素
  • 通过编辑第一个元素
  • 来考虑浮点数学

抱歉不知道C#,这是python:

import random
import time

PARTS       = 5
TOTAL       = 10
PLACES      = 3

def random_sum_split(parts, total, places):

    a = []
    for n in range(parts):
        a.append(random.random())
    b = sum(a)
    c = [x/b for x in a]    
    d = sum(c)
    e = c
    if places != None:
        e = [round(x*total, places) for x in c]
    f = e[-(parts-1):]
    g = total - sum(f)
    if places != None:
        g = round(g, places)
    f.insert(0, g)

    log(a)
    log(b)
    log(c)
    log(d)
    log(e)
    log(f)
    log(g)

    return f   

def tick():

    if info.tick == 1:

        start = time.time()

        alpha = random_sum_split(PARTS, TOTAL, PLACES)

        log('********************')
        log('***** RESULTS ******')
        log('alpha: %s' % alpha)
        log('total: %.7f' % sum(alpha))
        log('parts: %s' % PARTS)
        log('places: %s' % PLACES)

        end = time.time()  

        log('elapsed: %.7f' % (end-start))

yeilds:

Waiting...
Saved successfully.
[2014-06-13 00:01:00] [0.33561018369775897, 0.4904215932650632, 0.20264927800402832, 0.118862130636748, 0.03107818050878819]
[2014-06-13 00:01:00] 1.17862136611
[2014-06-13 00:01:00] [0.28474809073311597, 0.41609766067850096, 0.17193755673414868, 0.10084844382959707, 0.02636824802463724]
[2014-06-13 00:01:00] 1.0
[2014-06-13 00:01:00] [2.847, 4.161, 1.719, 1.008, 0.264]
[2014-06-13 00:01:00] [2.848, 4.161, 1.719, 1.008, 0.264]
[2014-06-13 00:01:00] 2.848
[2014-06-13 00:01:00] ********************
[2014-06-13 00:01:00] ***** RESULTS ******
[2014-06-13 00:01:00] alpha: [2.848, 4.161, 1.719, 1.008, 0.264]
[2014-06-13 00:01:00] total: 10.0000000
[2014-06-13 00:01:00] parts: 5
[2014-06-13 00:01:00] places: 3
[2014-06-13 00:01:00] elapsed: 0.0054131

答案 8 :(得分:0)

以@Simen和@Daren Thomas的答案为基础,这是一个服务函数,该函数返回具有统一随机值的双打列表,您可以在其中指定所需的数字,总和以及位数。数字:

        public static List<double> GetListOfRandomDoubles(int countOfNumbers, double totalSum, int digits)
        {
            Random r = new Random();

            List<double> randomDoubles = new List<double>();
            double totalRandomSum = 0; 

            for (int i = 0; i < countOfNumbers; i++)
            {
                double nextDouble = r.NextDouble();
                randomDoubles.Add(nextDouble);
                totalRandomSum += nextDouble;
            }

            double totalFactor = 1 / totalRandomSum;
            totalFactor = totalFactor * totalSum;

            for (int i = 0; i < randomDoubles.Count; i++)
            {
                randomDoubles[i] = randomDoubles[i] * totalFactor;
                randomDoubles[i] = Math.Round(randomDoubles[i], digits);
            }

            double currentRandomSum = 0;
            randomDoubles.ForEach(x => currentRandomSum += x);
            randomDoubles[0] += totalSum - currentRandomSum;

            return randomDoubles;
        }

用法:

        // Get list of 7 random doubles that sum to 100, with up to 2 digits on each number
        List<double> randomDoubles = GetListOfRandomDoubles(7, 100, 2);

返回:

12.25, 19.52, 15.49, 16.45, 1.92, 13.12, 21.25