Skip to content

Instantly share code, notes, and snippets.

@bryanedds
Created November 13, 2014 19:40
Show Gist options
  • Save bryanedds/bb77ac4277c9cd408393 to your computer and use it in GitHub Desktop.
Save bryanedds/bb77ac4277c9cd408393 to your computer and use it in GitHub Desktop.
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