[英]How to generate large number of gaussian random variables in Swift
我想創建大量從高斯分布中抽取的隨機數。 我找到了 dlarnv ,但我不確定如何在 Swift 中使用它。具體來說,類型簽名 XCode 顯示如下:
dlarnv_(
__idist: UnsafeMutablePointer<__CLPK_integer>,
__iseed: UnsafeMutablePointer<__CLPK_integer>,
__n: UnsafeMutablePointer<__CLPK_integer>,
__x: UnsafeMutablePointer<__CLPK_doublereal>
)
我如何使用它來用單精度浮點數填充數組? 這是我已經走了多遠:
n = 10000
var data: [Float]
data.reserveCapacity(n)
data
dlarnv_(
3, // for normal distribution
seed, // not sure how to seed
n,
data, // not sure how to pass a pointer
)
如果您一次想要很多值,並且希望它們服從標准正態分布 (µ=0, σ=1),那么很難擊敗dlarnv_
。 但如果您想要更多的靈活性,您還應該考慮 GKLinearCongruentialRandomSource 和一點數學知識。 一次獲取 1000 萬個值時,下面的代碼比dlarnv_
慢 20%,但如果您一次只需要一個值(包括調整均值和標准偏差),它會快 5 倍。
import GameplayKit
let random = GKLinearCongruentialRandomSource()
func randomNormalValue(average: Double, standardDeviation: Double) -> Double {
let x1 = Double(random.nextUniform())
let x2 = Double(random.nextUniform())
let z1 = sqrt(-2 * log(x1)) * cos(2 * .pi * x2)
return z1 * standardDeviation + average
}
我不確定為什么 GKGaussianDistribution 沒有以這種方式實現(或者其他可能更快的解決方案之一,但我沒有費心去實現和測試)。 我同意它很慢。
但它並沒有那么慢。 對於 10M 隨機值,它比dlarnv_
慢大約 75%。 這很慢,但仍然處於相同的數量級。 問題是隨機源本身。 大多數人這樣寫:
let random = GKRandomSource()
這絕對是最安全的答案。 但這是一種加密安全的熵源。 如果你正在做任何需要數字真正隨機的事情,那就是你應該使用的(並且dlarnv_
不這樣做,所以在某些情況下它是不安全的)。
但是,如果您只需要“有點隨機,但沒有人會嘗試利用它不是真正隨機的事實”,那么您需要的源是 GKLinearCongruentialRandomSource。 這讓 GKGaussianDistribution 與 Accelerate 進入了相同的范圍(2 倍,而不是數量級)。
您可能需要考慮 Accelerate 的 BNNS 庫中的隨機生成器:
func randomFloats(n: Int,
mean: Float,
standardDeviation: Float) -> [Float] {
let result = [Float](unsafeUninitializedCapacity: n) {
buffer, unsafeUninitializedCapacity in
guard
var arrayDescriptor = BNNSNDArrayDescriptor(
data: buffer,
shape: .vector(n)),
let randomNumberGenerator = BNNSCreateRandomGenerator(
BNNSRandomGeneratorMethodAES_CTR,
nil) else {
fatalError()
}
BNNSRandomFillNormalFloat(
randomNumberGenerator,
&arrayDescriptor,
mean,
standardDeviation)
unsafeUninitializedCapacity = n
BNNSDestroyRandomGenerator(randomNumberGenerator)
}
return result
}
使用dlarnv_
比使用GameplayKit
快得多
var n: Int32 = 500 // Array size
var d: Int32 = 3 // 3 for Normal(0, 1)
var seed: [Int32] = [1, 1, 1, 1] \\ Ideally pick a random seed
var x: [Double] = Array<Double>(unsafeUninitializedCapacity: Int(n)) { buffer, count in
dlarnv_(&d, &seed, &n, buffer.baseAddress)
count = Int(n)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.