在C ++中快速添加随机变量

时间:2012-10-24 08:12:15

标签: c++ performance random

短版:如何最有效地表示和添加由其实现列表给出的两个随机变量?

版本更长: 对于工作项目,我需要添加几个随机变量,每个变量由一个值列表给出。例如,兰德的实现。变种。 A是{1,2,3},B的实现是{5,6,7}。因此,我需要的是A + B的分布,即{1 + 5,1 + 6,1 + 7,2 + 5,2 + 6,2 + 7,3 + 5,3 + 6,3 + 7 }。对于不同的随机变量(C,D,...),我需要做几次这样的添加(让我们将这个数量的加法表示为COUNT,其中COUNT可能达到720)。

问题:如果我使用这个将A的每个实现与B的每个实现相加的愚蠢算法,复杂度在COUNT中是指数的。因此,对于每个r.v.由三个值给出,COUNT = 720的计算量是3 ^ 720~3.36xe ^ 343,这将持续到我们计算的日子结束:)更不用说在现实生活中,每个r.v.的长度。将是5000 +。

解决方案: 1 /第一种解决方案是使用我可以进行舍入的事实,即具有整数实现值。像这样,我可以代表每个r.v.作为向量,对于与实现相对应的索引,我的值为1(当r.v.具有此实现一次时)。所以对于一个r.v. A和实现的向量索引从0到10,表示A的向量将是[0,1,1,1,0,0,0 ...],B的表示将是[0,0,0, 0,0,1,1,1,0,0,10。现在我通过遍历这些向量来创建A + B,并执行与上面相同的操作(将每个A的实现与B的每个实现相加并将其编码为相同的向量结构,向量长度中的二次复杂度)。这种方法的好处是复杂性受到约束。这种方法的问题在于,在实际应用中,A的实现将在区间[-50000,50000]中,粒度为1.因此,在添加两个随机变量后,A + B的范围变为-100K ,100K ..和720次加法后,SUM(A,B,...)的跨度达到[-36M,36M]甚至二次复杂度(与指数复杂度相比),这个大型将永远需要。

2 /为了拥有更短的数组,人们可能会使用一个散列映射,这很可能会减少A + B中涉及的操作(数组访问)的数量,因为假设理论范围的某些非平凡部分[ -50K,50K]永远不会成为现实。然而,随着越来越多的随机变量的不断求和,实现的数量呈指数增长,而跨度仅线性增加,因此跨度中的数字密度随时间增加。这会破坏hashmap的好处。

所以问题是:我怎样才能有效地解决这个问题?计算电力交易中的VaR需要解决方案,其中所有分布都是凭经验给出的,并且不像普通分布,因此公式没有用,我们只能模拟。


使用数学被认为是我们部门的一半的第一选择。是数学家。但是,我们要添加的分布表现不佳,COUNT = 720是极端的。更有可能的是,我们将使用COUNT = 24来获得每日VaR。考虑到要添加的分布的不良行为,对于COUNT = 24,中心极限定理不会过于紧密(SUM(A1,A2,...,A24)的发音不会接近正常)。在我们计算可能的风险时,我们希望尽可能准确地得到一个数字。

预期用途是:您从某些操作中获得每小时的casflow。一小时的现金流量分配是r.v. A.接下来的一个小时,它是r.v. B等等。你的问题是:99%的案件中最大的损失是什么?因此,您为这24小时中的每一小时模拟现金流量,并将这些现金流量作为随机变量添加,以便在一整天内获得总流量的分布。然后你取0.01分位数。

4 个答案:

答案 0 :(得分:1)

尝试减少进行整个添加所需的传递次数,可能会将其减少到每个列表的一次传递,包括最后一个。

我认为你不能减少总数。

此外,如果适用,您应该研究并行算法和多线程。

此时,大多数处理器能够在给定适当的指令(SSE)的情况下并行执行添加,这将使添加速度提高许多倍(仍然无法解决复杂性问题)。

答案 1 :(得分:1)

正如你在问题中所说,你需要大量的计算来得到确切的答案。所以它不会发生。

但是,当您处理随机值时,可以将一些数学应用于问题。所有这些添加的结果不会导致接近正态分布的东西吗?例如,考虑滚动一个骰子。每个数字具有相同的概率,因此实现不遵循正态分布(实际上,他们可能会这样做,上周BBC4上有一个关于它的程序,它表明彩票球的外观正常分布)。但是,如果您滚动两个骰子并对它们求和,那么实现确实遵循正态分布。所以我认为你的计算结果将接近正态分布,因此它成为找到给定输入集的平均值和西格玛值的问题。你可以训练每个输入的上限和下限以及它们的平均值。我确信谷歌搜索将提供将函数应用于正态分布的方法。

我想有一个推论问题,结果是用于什么?了解结果的使用方式将为决定如何创建结果提供信息。

答案 2 :(得分:1)

忽略程序化解决方案,随着数据集的增长,您可以非常显着地减少添加的总数。

如果我们定义了四个组WXYZ,每个组都有三个元素,根据您自己的数学运算会导致大量操作:

  • W + X => 9次行动
  • (W + X)+ Y => 27次行动
  • (W + X + Y)+ Z => 81次行动
  • TOTAL:117次操作

但是,如果我们假设您对“添加”操作进行了严格排序的定义,那么两组{a,b}{c,d}始终会生成{a+c,a+d,b+c,b+d},那么您的操作就是 { {3}} 的。这意味着你可以这样做:

  • W + X => 9次行动
  • Y + Z => 9次行动
  • (W + X)+(Y + Z)=> 81次行动
  • TOTAL:99次操作

对于一个简单的案例,这节省了18次操作。如果将上述内容扩展到6组3个成员,则操作总数可以从1089减少到837 - 几乎节省20%。这种改进越明显,您拥有的数据就越多(更多集合或更多元素将带来更多节省)。

此外,这可以解决更好的并行化问题:如果你有200个组要处理,你可以先并行组合100对,然后是50对或结果,然后是25,等等。这将允许很大程度上并行性应该会给你带来更好的性能。 (例如,在~10个并行操作中将添加720个集合,因为每个并行添加将允许将COUNT增加2倍。)

我绝对不是这方面的专家,但对于使用典型GPU的并行处理功能来说这似乎是一个理想的问题 - 我的理解是像CUDA这样的东西可以简单地并行处理所有这些计算。 / p>

编辑:如果你真正的问题是“你最大的损失是什么”,那么这是一个更容易解决的问题。假设最终集合中的每个值都是每个“组件”集合中一个值的总和,那么通常可以通过组合每个组件集的最低值来找到最大的损失。找到这些较低的值(每组一个值)是一个更简单的工作,然后您只需要将有限的一组值相加。

答案 3 :(得分:0)

基本上有两种方法。一个近似的和一个确切的...

近似方法通过大量采样来模拟随机变量的总和。基本上,随机变量AB我们从每个r.v中随机抽样。 50K次,添加采样值(这里SSE可以帮助很多),我们的分布为A+B。这就是数学家在Mathematica中如何做到这一点。

确切方法利用Dan Puzey提出的一些东西,即仅将每个r.v.密度的一小部分相加。假设我们有随机变量,其中包含以下“密度”(为简单起见,每个值具有相同的可能性)

A = {-5,-3,-2}
B = {+0,+1,+2}
C = {+7,+8,+9}

A+B+C的总和将是

{2,3,3,4,4,4,4,5,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,8,8,8,9}

如果我想准确地知道整个分布,除了将A的每个元素与B的每个元素相加,然后将每个元素与C的每个元素相加,我别无选择。但是,如果我只想要该总和的99%VaR,即该总和的1%百分比,我只需求A,B,C的最小元素。

更确切地说,我将从每个分布中获取nA,nB,nC个最小元素。要确定nA,nB,nC,请先将它们设置为1。然后,如果nA(依据A[nA] = min( A[nA], B[nB], C[nC])进行排序),请将A,B,C增加1。这样,我可以得到nA, nB, nC A,B,C的最小元素,我必须将它们相加(每个元素彼此相加)并取第X个最小的和(其中X是1%乘以总数)总和的组合计数,即A,B,C)的3 * 3 * 3。这也说明何时停止增加nA,nB,nC - 在nA*nB*nC>时停止X

然而,像这样我再次做同样的冗余,即我正在计算1%百分位左A+B+C的整个分布。然而,这比计算A+B+C的整个发行版要短得多。但我相信应该有一个简单的迭代算法来告诉exaclty O(a*b)中给定的VaR数,其中a是添加的rv数,b是元素中的最大元素数。每个rv的密度

对于我是否正确,我会很高兴。