Avendo bisogno di un generatore di numeri casuali che restituisce un campione da una distribuzione normale (gaussiana), ho portato su F # una porzione di John D. Cook's C# generator:thread-safe normale generatore di numeri casuali in F #
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() |]
questa implementazione opere bene, ma non è thread-safe. Dato che il codice che dipende da esso fa ampio uso della Libreria parallela di Thread, ho bisogno di renderlo thread-safe.
Questo non mi sembra ovvio perché al centro del metodo si trovano due membri mutabili che sono praticamente indispensabili. C'è un altro modo per raggiungere la sicurezza del filo senza ricorrere alle serrature?
Esiste un altro modo per implementare un normale generatore pseudo-casuale utilizzando solo membri immutabili?
Buona chiamata per non chiamare setSeed ogni volta, stupido controllo –
Mi piace questa idea. Potresti per favore elaborare l'opzione di espressione di calcolo (non ho familiarità con il concetto)? –
Assomiglierebbe a qualcosa: 'rnd { let! a = GetNext 10; let! b = GetExponential 2.5; let! c = GetNormal; return a, b, c } ' – IngisKahn