Last active
May 20, 2016 19:27
-
-
Save drhurdle/a7f5faf7fa7c893031dfd64621bc3763 to your computer and use it in GitHub Desktop.
Pseudo-Random Number generator utilizing xoroshiro128+ algorithm in Swift 2.2
This file contains 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
import Foundation | |
/// Pseudo-Random Number generator utilizing xoroshiro128+ algorithm | |
/// translated from: http://xoroshiro.di.unimi.it/xoroshiro128plus.c | |
/// Example: | |
/* | |
var myRNG = RNG() | |
var x = myRNG.getRandomNumber(0,100) | |
var r = RNG(seed: 2345) // Seed is the same as {s} below | |
var s = RNG(seed: 2345) // Seed is the same as {r} above | |
var t = RNG(seed: 3456) // Seed is different from {s} and {r} | |
var sameSeedR = r.getRandomNumber() | |
var sameSeedS = s.getRandomNumber() // sameSeedS == sameSeedR | |
var diffSeedT = t.getRandomNumber() // totally different | |
*/ | |
/// Main Pseudo-Random Number Generator | |
public struct RNG { | |
var seed: UInt64 | |
var rngState: [UInt64] = [0, 0] | |
var generator: Xoroshiro128Plus | |
public init(seed: UInt64 = UInt64(NSDate().timeIntervalSinceReferenceDate)) { | |
self.seed = seed | |
self.generator = Xoroshiro128Plus(state: [0, 0]) | |
generateSeeds(seed) | |
self.generator.state = rngState | |
getRandomNumber() | |
} | |
private mutating func generateSeeds(seed: UInt64){ | |
var seeder = SplitMix64(state: seed) | |
var statePart: UInt64 | |
for x in 0...10 { | |
statePart = seeder.nextSeed() | |
rngState[0] = x == 9 ? statePart : 0 | |
rngState[1] = x == 10 ? statePart : 0 | |
} | |
} | |
/// Retrieves a random number with an optional range | |
/// - parameter min: (OPTIONAL) defines minimum value for a range that return value should be within | |
/// - parameter max: (OPTIONAL) defines maximum value for a range that return value should be within | |
/// - returns: returns the next random UInt64 in the sequence | |
public mutating func getRandomNumber(min: UInt64 = 0, max: UInt64 = UInt64.max - 1) -> UInt64 { | |
return generator.next() % (max - min + 1) + min | |
} | |
} | |
/// Main algorithm for generating pseudo-random numbers | |
internal struct Xoroshiro128Plus { | |
var state: [UInt64] | |
func rotateLeft(a: UInt64, b: UInt64) -> UInt64 { | |
return (a << b) | (a >> (64 - b)) | |
} | |
mutating func next() -> UInt64 { | |
let s0: UInt64 = state[0] | |
var s1 = state[1] | |
let result: UInt64 = s0 &+ s1 | |
s1 ^= s0 | |
state[0] = rotateLeft(s0, b: 55) ^ s1 ^ (s1 << 14) | |
state[1] = rotateLeft(s1, b: 36) | |
return result | |
} | |
} | |
/// Creates seed values to be used in Xoroshiro128Plus algorithm | |
internal struct SplitMix64 { | |
var state: UInt64 | |
mutating func nextSeed() -> UInt64 { | |
var b: UInt64 = state &+ 0x9E3779B97F4A7C15 | |
b = (b ^ (b >> 30)) ^ 0xBF58476D1CE4E5B9 | |
b = (b ^ (b >> 27)) ^ 0x94D049BB133111EB | |
state = b ^ (b >> 31) | |
return state | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment