(Como essa abordagem é independente das outras soluções postadas, incluindo uma que eu publiquei, estou oferecendo-a como uma resposta separada).
Você pode calcular a distribuição exata em segundos (ou menos), desde que a soma dos p's seja pequena.
Já vimos sugestões de que a distribuição possa ser aproximadamente gaussiana (em alguns cenários) ou Poisson (em outros cenários). De qualquer maneira, sabemos que sua média é a soma de p i e sua variância σ 2 é a soma de p i ( 1 - p i ) . Portanto, a distribuição será concentrada dentro de alguns desvios padrão de sua média, digamos z SDs com z entre 4 e 6 ou aproximadamente. Portanto, precisamos calcular apenas a probabilidade de que a soma X seja igual (um número inteiro) k para k = μμpiσ2pi(1−pi)zzXk através de k = μ + z σ . Quando a maior parte do p ik=μ−zσk=μ+zσpi são pequeno, é aproximadamente igual a (mas ligeiramente menor do que) μ , de modo a ser conservadora que pode fazer o cálculo para k no intervalo [ μ - z √σ2μk. Por exemplo, quando a soma depié igual a9e a escolha dez=6para cobrir bem as caudas, precisaríamos do cálculo para cobrirkem[9-6 √[μ−zμ−−√,μ+zμ−−√]pi9z=6k=[0,27], que são apenas 28 valores.[9−69–√,9+69–√][0,27]
A distribuição é calculada recursivamente . Vamos ser a distribuição da soma do primeiro i dessas variáveis Bernoulli. Para qualquer j de 0 a i + 1 , a soma das primeiras variáveis i + 1 pode ser igual a j de duas maneiras mutuamente exclusivas: a soma das primeiras variáveis i é igual a j e o i + 1 st é 0 ou então a soma de a primeira i variáveis é igual a j - 1 e afiij0i+1i+1jiji+1st0ij−1i+1st is 1. Therefore
fi+1(j)=fi(j)(1−pi+1)+fi(j−1)pi+1.
We only need to carry out this computation for integral j in the interval from max(0,μ−zμ−−√) to μ+zμ−−√.
When most of the pi are tiny (but the 1−pi are still distinguishable from 1 with reasonable precision), this approach is not plagued with the huge accumulation of floating point roundoff errors used in the solution I previously posted. Therefore, extended-precision computation is not required. For example, a double-precision calculation for an array of 216 probabilities pi=1/(i+1) (μ=10.6676, requiring calculations for probabilities of sums between 0 and 31) took 0.1 seconds with Mathematica 8 and 1-2 seconds with Excel 2002 (both obtained the same answers). Repeating it with quadruple precision (in Mathematica) took about 2 seconds but did not change any answer by more than 3×10−15. Terminating the distribution at z=6 SDs into the upper tail lost only 3.6×10−8 of the total probability.
Another calculation for an array of 40,000 double precision random values between 0 and 0.001 (μ=19.9093) took 0.08 seconds with Mathematica.
This algorithm is parallelizable. Just break the set of pi into disjoint subsets of approximately equal size, one per processor. Compute the distribution for each subset, then convolve the results (using FFT if you like, although this speedup is probably unnecessary) to obtain the full answer. This makes it practical to use even when μ gets large, when you need to look far out into the tails (z large), and/or n is large.
The timing for an array of n variables with m processors scales as O(n(μ+zμ−−√)/m). Mathematica's speed is on the order of a million per second. For example, with m=1 processor, n=20000 variates, a total probability of μ=100, and going out to z=6 standard deviations into the upper tail, n(μ+zμ−−√)/m=3.2 million: figure a couple seconds of computing time. If you compile this you might speed up the performance two orders of magnitude.
Incidentally, in these test cases, graphs of the distribution clearly showed some positive skewness: they aren't normal.
For the record, here is a Mathematica solution:
pb[p_, z_] := Module[
{\[Mu] = Total[p]},
Fold[#1 - #2 Differences[Prepend[#1, 0]] &,
Prepend[ConstantArray[0, Ceiling[\[Mu] + Sqrt[\[Mu]] z]], 1], p]
]
(NB The color coding applied by this site is meaningless for Mathematica code. In particular, the gray stuff is not comments: it's where all the work is done!)
An example of its use is
pb[RandomReal[{0, 0.001}, 40000], 8]
Edit
An R
solution is ten times slower than Mathematica in this test case--perhaps I have not coded it optimally--but it still executes quickly (about one second):
pb <- function(p, z) {
mu <- sum(p)
x <- c(1, rep(0, ceiling(mu + sqrt(mu) * z)))
f <- function(v) {x <<- x - v * diff(c(0, x));}
sapply(p, f); x
}
y <- pb(runif(40000, 0, 0.001), 8)
plot(y)