diff --git a/Sources/EcgSynKit/SplitMix64.swift b/Sources/EcgSynKit/SplitMix64.swift new file mode 100644 index 0000000..e28a8fe --- /dev/null +++ b/Sources/EcgSynKit/SplitMix64.swift @@ -0,0 +1,21 @@ + +struct SplitMix64 : RandomNumberGenerator { + public typealias State = UInt64 + public private(set) var state: State + + init(state: UInt64) { + self.state = state + } + + public mutating func next() -> UInt64 { + state &+= 0x9E3779B97F4A7C15 + var z = state + z = (z ^ (z >> 30)) &* 0xBF58476D1CE4E5B9 + z = (z ^ (z >> 27)) &* 0x94D049BB133111EB + return z ^ (z >> 31) + } + + public mutating func nextDouble() -> Double { + Double(next() >> 11) * 0x1.0p-53 + } +} diff --git a/Sources/EcgSynKit/Xoshiro256Plus.swift b/Sources/EcgSynKit/Xoshiro256Plus.swift new file mode 100644 index 0000000..50998f2 --- /dev/null +++ b/Sources/EcgSynKit/Xoshiro256Plus.swift @@ -0,0 +1,63 @@ +import Foundation + +public enum Xoshiro256: Equatable { + public typealias State = (UInt64, UInt64, UInt64, UInt64) + + internal static var invalidState: State { (0, 0, 0, 0) } + + internal static func isValid(state: State) -> Bool { + state != invalidState + } +} + +@inlinable +@inline(__always) +internal func rotl(_ x: UInt64, _ k: UInt64) -> UInt64 { + (x << k) | (x >> (64 &- k)) +} + +struct Xoshiro256Plus: RandomNumberGenerator { + public typealias State = Xoshiro256.State + + private var state: State + + public init() { + var generator = SystemRandomNumberGenerator() + self.init(seed: generator.next()) + } + + public init(seed: UInt64) { + var generator = SplitMix64(state: seed) + var state = Xoshiro256.invalidState + + repeat { + state = (generator.next(), generator.next(), generator.next(), generator.next()) + } while !Xoshiro256.isValid(state: state) + + self.init(state: state) + } + + public init(state: State) { + precondition(Xoshiro256.isValid(state: state), "The state must not be zero") + self.state = state + } + + public mutating func next() -> UInt64 { + let result = state.0 &+ state.3 + let t = state.1 << 17 + + state.2 ^= state.0 + state.3 ^= state.1 + state.1 ^= state.2 + state.0 ^= state.3 + + state.2 ^= t + state.3 = rotl(state.3, 45) + + return result + } + + public mutating func nextDouble() -> Double { + Float64(next() >> 11) * 0x1.0p-53 + } +}