split split mix sixty four

This commit is contained in:
a dinosaur 2024-09-01 02:09:49 +10:00
parent c99155fb47
commit 1f74b79ea2
6 changed files with 62 additions and 60 deletions

View File

@ -28,6 +28,7 @@ add_executable(Voxelotl MACOSX_BUNDLE
Random/PerlinNoiseGenerator.swift
Random/SimplexNoise.swift
Random/RandomCollectionExtensions.swift
Random/SplitMix64.swift
# Resource classes
NSImageLoader.swift

View File

@ -1,5 +1,6 @@
public struct PCG32Random: RandomProvider, RandomStateAccess {
public struct PCG32Random: RandomProvider, RandomSeedable, RandomStateAccess {
public typealias Output = UInt32
public typealias SeedType = (UInt64, UInt64)
public typealias StateType = (UInt64, UInt64)
public static var min: UInt32 { .min }
@ -21,11 +22,20 @@ public struct PCG32Random: RandomProvider, RandomStateAccess {
}
public init(state: (UInt64, UInt64)) {
self.init()
self.reset(state: state.0, sequence: state.1)
self._state = state.0
self._inc = state.1
}
public mutating func reset(state: UInt64, sequence: UInt64) {
public init(seed: (UInt64, UInt64)) {
self.init()
self.seed(state: seed.0, sequence: seed.1)
}
public mutating func seed(_ seed: (UInt64, UInt64)) {
self.seed(state: seed.0, sequence: seed.1)
}
public mutating func seed(state: UInt64, sequence: UInt64) {
self._state = 0
self._inc = sequence << 1 | 0x1
_ = next()

View File

@ -8,7 +8,7 @@ public protocol RandomProvider {
}
public protocol RandomSeedable {
associatedtype SeedType: FixedWidthInteger
associatedtype SeedType
init(seed: SeedType)
mutating func seed(_ value: SeedType)

View File

@ -0,0 +1,25 @@
public struct SplitMix64: RandomProvider, RandomSeedable {
public typealias Output = UInt64
public typealias SeedType = UInt64
public static var min: UInt64 { .max }
public static var max: UInt64 { .min }
private var _state: UInt64
public init(seed: UInt64) {
self._state = seed
}
public mutating func seed(_ value: UInt64) {
self._state = value
}
public mutating func next() -> UInt64 {
var x = self._state &+ 0x9E3779B97F4A7C15
x = (x ^ x &>> 30) &* 0xBF58476D1CE4E5B9
x = (x ^ x &>> 27) &* 0x94D049BB133111EB
self._state = x ^ x &>> 31
return self._state
}
}

View File

@ -1,10 +1,9 @@
struct Xoroshiro128Plus: RandomProvider, RandomSeedable, RandomStateAccess {
public struct Xoroshiro128Plus: RandomProvider, RandomStateAccess {
public typealias Output = UInt64
public typealias SeedType = UInt64
public typealias StateType = (UInt64, UInt64)
static public var min: UInt64 { .min }
static public var max: UInt64 { .max }
public static var min: UInt64 { .min }
public static var max: UInt64 { .max }
public var state: (UInt64, UInt64)
@ -16,16 +15,6 @@ struct Xoroshiro128Plus: RandomProvider, RandomSeedable, RandomStateAccess {
self.state = (state.0, state.1)
}
public init(seed: UInt64) {
let s0 = splitMix64(seed: seed)
self.init(state: (s0, splitMix64(seed: s0)))
}
public mutating func seed(_ seed: UInt64) {
let s0 = splitMix64(seed: seed)
self.state = (s0, splitMix64(seed: s0))
}
public mutating func next() -> UInt64 {
let result = self.state.0 &+ self.state.1
@ -38,13 +27,12 @@ struct Xoroshiro128Plus: RandomProvider, RandomSeedable, RandomStateAccess {
}
}
struct Xoroshiro128PlusPlus: RandomProvider, RandomSeedable, RandomStateAccess {
public struct Xoroshiro128PlusPlus: RandomProvider, RandomStateAccess {
public typealias Output = UInt64
public typealias SeedType = UInt64
public typealias StateType = (UInt64, UInt64)
static public var min: UInt64 { .min }
static public var max: UInt64 { .max }
public static var min: UInt64 { .min }
public static var max: UInt64 { .max }
public var state: (UInt64, UInt64)
@ -56,16 +44,6 @@ struct Xoroshiro128PlusPlus: RandomProvider, RandomSeedable, RandomStateAccess {
self.state = (state.0, state.1)
}
public init(seed: UInt64) {
let s0 = splitMix64(seed: seed)
self.init(state: (s0, splitMix64(seed: s0)))
}
public mutating func seed(_ seed: UInt64) {
let s0 = splitMix64(seed: seed)
self.state = (s0, splitMix64(seed: s0))
}
public mutating func next() -> UInt64 {
let result = (self.state.0 &+ self.state.1).rotate(left: 17) &+ self.state.0
@ -78,13 +56,12 @@ struct Xoroshiro128PlusPlus: RandomProvider, RandomSeedable, RandomStateAccess {
}
}
struct Xoroshiro128StarStar: RandomProvider, RandomSeedable, RandomStateAccess {
public struct Xoroshiro128StarStar: RandomProvider, RandomStateAccess {
public typealias Output = UInt64
public typealias SeedType = UInt64
public typealias StateType = (UInt64, UInt64)
static public var min: UInt64 { .min }
static public var max: UInt64 { .max }
public static var min: UInt64 { .min }
public static var max: UInt64 { .max }
public var state: (UInt64, UInt64)
@ -96,16 +73,6 @@ struct Xoroshiro128StarStar: RandomProvider, RandomSeedable, RandomStateAccess {
self.state = (state.0, state.1)
}
public init(seed: UInt64) {
let s0 = splitMix64(seed: seed)
self.init(state: (s0, splitMix64(seed: s0)))
}
public mutating func seed(_ seed: UInt64) {
let s0 = splitMix64(seed: seed)
self.state = (s0, splitMix64(seed: s0))
}
public mutating func next() -> UInt64 {
let result = (self.state.0 &* 5).rotate(left: 7) &* 9
@ -119,14 +86,7 @@ struct Xoroshiro128StarStar: RandomProvider, RandomSeedable, RandomStateAccess {
}
fileprivate extension UInt64 {
func rotate(left count: Int) -> Self {
@inline(__always) func rotate(left count: Int) -> Self {
self &<< count | self &>> (Self.bitWidth &- count)
}
}
fileprivate func splitMix64(seed: UInt64) -> UInt64 {
var x = seed &+ 0x9E3779B97F4A7C15
x = (x ^ x &>> 30) &* 0xBF58476D1CE4E5B9
x = (x ^ x &>> 27) &* 0x94D049BB133111EB
return x ^ x &>> 31
}

View File

@ -3,13 +3,11 @@ struct WorldGenerator {
public mutating func reset(seed: UInt64) {
var random: any RandomProvider
let initialState = SplitMix64.createState(seed: seed)
#if true
random = Xoroshiro128PlusPlus(seed: seed)
random = Xoroshiro128PlusPlus(state: initialState)
#else
//TODO: Fill seed with a hash
random = PCG32Random(state: (
UInt64(Arc4Random.instance.next()) | UInt64(Arc4Random.instance.next()) << 32,
UInt64(Arc4Random.instance.next()) | UInt64(Arc4Random.instance.next()) << 32))
random = PCG32Random(seed: initialState)
#endif
self.noise = ImprovedPerlin<Float>(random: &random)
@ -38,3 +36,11 @@ struct WorldGenerator {
return chunk
}
}
fileprivate extension RandomProvider where Output == UInt64, Self: RandomSeedable, SeedType == UInt64 {
static func createState(seed value: UInt64) -> (UInt64, UInt64) {
var hash = Self(seed: value)
let state = (hash.next(), hash.next())
return state
}
}