在F#中的线程安全正常的随机数发生器随机数、发生器、线程、正常

2023-09-03 16:44:39 作者:逆袭吧Juvenile

孤男寡女一个随机数发生器,它返回从正常(高斯)分布的样品,我已经移植到的F#的约翰·库克的C#发电机的:

Needing a random number generator that returns a sample from a normal (Gaussian) distribution, I've ported to F# a portion of John D. Cook's C# generator:

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 () |]

本实施工作正常,但不是线程安全的。鉴于code依赖于它大量使用了线程并行库,我需要使它线程安全的。

This implementation works fine but is not thread safe. Given that the code that depends on it makes extensive use of the Thread Parallel Library, I need to make it thread safe.

这看起来并不明显,我因为在方法谎言2可变会员,分别是pretty的太多不可缺少的核心。有没有实现线程安全,而不诉诸锁的任何其他方式?

This does not look obvious to me because at the core of the method lie two mutable members which are pretty much indispensable. Is there any other way to achieve thread-safety without resorting to locks?

有没有只用一成不变的成员实行正常的伪随机数发生器的任何其他方式?

Is there any other way to implement a normal pseudo-random generator using only immutable members?

推荐答案

使用可变成员,你没有选择,只能使用一个锁。

Using mutable members, you'd have no choice but use a lock.

不过,你会更好地与一个不变的记录包含 M_W m_z 您传递给你的随机函数。他们可以回到你的随机值的元组,并包含更新的随机成员的新​​纪录。更重要的是,你可以创建一个计算EX pression 处理产生偶合,所以你赢了T担心绕过随机记录。

However, you'd be better off with an immutable record containing m_w and m_z that you pass to your random functions. They could return a tuple of your random value and a new record containing the updated random members. Better yet, you could create a computation expression to handle generating randoms so you won't have to worry about passing the random record around.

此外,调用过setSeed 从您的随机函数是坏的。多个后续调用将返回相同的山谷。你只需要设置你的后裔一次。

Also, calling setSeed from within your random functions is bad. Multiple subsequent calls will return the same vale. You only want to set your seed once.