Поточно-безопасный генератор обычных случайных чисел на F#

Нужен генератор случайных чисел, который возвращает выборку из нормального (гауссовского) распределения, я портировал на F# часть генератора C# Джона Д. Кука:

let mutable m_w = 521288629u
let mutable m_z = 362436069u

let private getUint () =
    m_z <- 36969u * (m_z &&& 65535u) + (m_z >>> 16)
    m_w <- 18000u * (m_w &&& 65535u) + (m_w >>> 16)
    (m_z <<< 16) + m_w

let private setSeed () =
    let dt = System.DateTime.Now
    let x = dt.ToFileTime ()
    m_w <- uint32 (x >>> 16)
    m_z <- uint32 (x % 4294967296L)

let private getUniform () =
    let u = getUint ()
    (float u + 1.) * 2.328306435454494e-10

let private randomNormal () =
    let u1 = getUniform ()
    let u2 = getUniform ()
    let r = sqrt (-2. * (log u1))
    let theta = 2. * System.Math.PI * u2
    r * sin (theta)

/// Returns a normal (Gaussian) random sample with mean 0 and standard deviation 1
let randn () =
    setSeed ()
    randomNormal ()

/// Returns an array of normal (Gaussian) random samples
let randns n m =
    setSeed ()
    [| for i in 0 .. n - 1 -> randomNormal () |]

Эта реализация работает нормально, но не является потокобезопасной. Учитывая, что код, который зависит от него, широко использует библиотеку параллельных потоков, мне нужно сделать его потокобезопасным.

Это не кажется мне очевидным, потому что в основе метода лежат два изменяемых члена, которые в значительной степени незаменимы. Есть ли другой способ добиться потокобезопасности, не прибегая к блокировкам?

Есть ли другой способ реализовать нормальный генератор псевдослучайных чисел, используя только неизменяемые элементы?

5
задан Francesco De Vittori 2 May 2012 в 15:42
поделиться