如何生成三个随机数,它们的和为1
本文关键字:随机数 何生成 三个 | 更新日期: 2023-09-27 17:49:26
我需要生成3个随机数,其数量等于1。
我的实现不支持统一分布。(
只是得到3个随机数字,然后计算一个因子是1/[你的数字的总和]。最后将每个随机数与该因子相乘。和为1
这实际上是一个棘手的问题。首先:
Daren的解决方案不是统一的,因为它不支持两个> 1/3的数字。
Simen的解决方案是不均匀的,假设"选择一个随机数"从均匀分布中提取,但这有点微妙。它至少在变量之间是对称的(即[a, b, c]的概率与它的任何排列的概率相同),但它更倾向于接近(1/3,1/3,1/3)的解。通过观察极端情况来思考这个问题:(1/3, 1/3, 1/3)可以来自任意(a, a, a)其中a的取值范围是0到1。(1,0,0),同样有效的三元组,必须来自(1,0,0)。
一种解:在三维空间中,正数加1形成一个n等边三角形,其坐标为(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。
——
生成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
UPDATE
- 创建一个由3个随机数组成的矢量
- 归一化矢量
Marnix的回答略有不同:
- 从[0,1]生成随机数
a
- 生成两个随机数。
x
from [0,a]和y
from [a,1] - 设置结果为
x
,y-x
,1-y
有一种简单的方法可以做到这一点,但是您需要能够生成一个统一的随机数。
设X在(0,2/3)上是一致的。如果X
在此设置下,X, Y和Z的总和为1,它们都将具有相同的均匀(0,2/3)边际分布,并且所有三个成对相关性将为-(1/2)。
1/2方法:
- 创建一个随机数列表,每个随机数的长度为0到1。
- 对列表求和
- 每个元素除以总和
- 每个元素四舍五入
- 通过编辑第一个元素 来计算浮点数
对不起,我不懂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))
让步:
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
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
基于@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