Created
November 13, 2014 19:40
-
-
Save bryanedds/bb77ac4277c9cd408393 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Prime | |
open System | |
[<AutoOpen>] | |
module RandModule = | |
/// Implements an immutable random number generator using the xorshift* algorithm. | |
/// NOTE: this is POORLY tested - would not recommend using until tested properly! | |
type [<StructuralEquality; NoComparison>] Rand = | |
{ Current : uint64 } | |
[<RequireQualifiedAccess>] | |
module Rand = | |
let make seed = | |
if seed = 0UL then failwith "Seed for Rand may not be zero." | |
{ Current = seed } | |
let makeFromInt (seed : int) = | |
let seedMultiplier = UInt64.MaxValue / uint64 UInt32.MaxValue | |
let seedUi64 = uint64 seed * seedMultiplier | |
make seedUi64 | |
let makeDefault () = | |
// NOTE: number generated via http://www.random.org/bytes/ | |
make 0xa529cb6f5f0385edUL | |
let advance rand = | |
let c = rand.Current | |
let c = c ^^^ (c >>> 12) | |
let c = c ^^^ (c <<< 25) | |
let c = c ^^^ (c >>> 27) | |
{ Current = c } | |
let sample rand = | |
rand.Current * 2685821657736338717UL | |
let sampleBytes rand = | |
let sampleUlong = sample rand | |
[|byte (sampleUlong >>> (7 * 8)) | |
byte (sampleUlong >>> (6 * 8)) | |
byte (sampleUlong >>> (5 * 8)) | |
byte (sampleUlong >>> (4 * 8)) | |
byte (sampleUlong >>> (3 * 8)) | |
byte (sampleUlong >>> (2 * 8)) | |
byte (sampleUlong >>> (1 * 8)) | |
byte sampleUlong|] | |
let nextSingle rand = | |
let rand = advance rand | |
let sampleBytes = sampleBytes rand | |
let sampleSingle = BitConverter.ToSingle (sampleBytes, 0) | |
let number = | |
if Single.IsNaN sampleSingle then 0.0f | |
elif Single.IsPositiveInfinity sampleSingle then Single.MaxValue | |
elif Single.IsNegativeInfinity sampleSingle then -Single.MaxValue | |
else sampleSingle | |
(number, rand) | |
let nextSingle2 max rand = | |
let (numberSingle, rand) = nextSingle rand | |
(numberSingle % max, rand) | |
let nextInt rand = | |
let rand = advance rand | |
let sampleInt = int (sample rand >>> 32) | |
// NOTE: System.Random.Next () will never return Int32.MaxValue, but this will. Any idea if | |
// we're taking the wrong approach? | |
let number = if sampleInt < 0 then sampleInt + Int32.MaxValue else sampleInt | |
(number, rand) | |
let nextInt2 max rand = | |
let (numberInt, rand) = nextInt rand | |
(numberInt % max, rand) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment