簡體   English   中英

Swift中如何產生大量的高斯隨機變量

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM