3 回答


TA貢獻1869條經驗 獲得超4個贊
您的代碼正在抽樣一個二項式隨機變量B(N,p),其中N是試驗次數(此處為1M),p是成功進行單個試驗的概率(此處為0.0003)。
一種方法是建立一個累積概率表T,其中T [i]包含試驗總數小于或等于i的概率。要生成樣本,您可以選擇一個統一的隨機變量(通過rand.Float64),然后在表中找到包含大于或等于該概率的第一個索引。
這里有點復雜,因為您有一個非常大的N和一個相當小的p,因此,如果您嘗試構建表,那么數字和算術精度就會非常麻煩。但是您可以構建一個較小的表(假設有1000個大表)并對其進行1000次采樣,以進行一百萬次試用。
這是完成所有這些工作的一些代碼。它不太優雅(1000 是硬編碼的),但它在我的舊筆記本電腦上不到一秒鐘就生成了 1000 次模擬。通過例如將BinomialSampler的構造從循環中移出,或者通過使用二進制搜索而不是線性掃描來查找表索引,可以很容易地進一步優化。
package main
import (
"fmt"
"math"
"math/rand"
)
type BinomialSampler []float64
func (bs BinomialSampler) Sample() int {
r := rand.Float64()
for i := 0; i < len(bs); i++ {
if bs[i] >= r {
return i
}
}
return len(bs)
}
func NewBinomialSampler(N int, p float64) BinomialSampler {
r := BinomialSampler(make([]float64, N+1))
T := 0.0
choice := 1.0
for i := 0; i <= N; i++ {
T += choice * math.Pow(p, float64(i)) * math.Pow(1-p, float64(N-i))
r[i] = T
choice *= float64(N-i) / float64(i+1)
}
return r
}
func WowSample(N int, p float64) int {
if N%1000 != 0 {
panic("N must be a multiple of 1000")
}
bs := NewBinomialSampler(1000, p)
r := 0
for i := 0; i < N; i += 1000 {
r += bs.Sample()
}
return r
}
func main() {
for i := 0; i < 1000; i++ {
fmt.Println(WowSample(1000000, 0.0003))
}
}
- 3 回答
- 0 關注
- 265 瀏覽
添加回答
舉報