diff --git a/spec/xoshiro128plus_spec.cr b/spec/xoshiro128plus_spec.cr index 266e7e9..4e43671 100644 --- a/spec/xoshiro128plus_spec.cr +++ b/spec/xoshiro128plus_spec.cr @@ -76,7 +76,7 @@ describe Random::XoShiRo128Plus do original.next_u.should eq(0x472255cc_u32) rng = original.split - rng.should_not be(original) - rng.next_u.should eq(0xbbc0480a_u32) + rng.should_not eq(original) + rng.next_u.should eq(0x16d92aa0_u32) end end diff --git a/spec/xoshiro128starstar_spec.cr b/spec/xoshiro128starstar_spec.cr index d7c7da1..7f0eea5 100644 --- a/spec/xoshiro128starstar_spec.cr +++ b/spec/xoshiro128starstar_spec.cr @@ -73,10 +73,11 @@ describe Random::XoShiRo128StarStar do end it "#split" do - rng = Random::XoShiRo128StarStar.new(0xdeadbeef_u64) - rng.next_u.should eq(0xa9c3d393_u32) + original = Random::XoShiRo128StarStar.new(0xdeadbeef_u64) + original.next_u.should eq(0xa9c3d393_u32) - rng = rng.split - rng.next_u.should eq(0x61800258_u32) + rng = original.split + rng.should_not eq(original) + rng.next_u.should eq(0x818871d8_u32) end end diff --git a/spec/xoshiro256plus_spec.cr b/spec/xoshiro256plus_spec.cr index ba9827d..0daf865 100644 --- a/spec/xoshiro256plus_spec.cr +++ b/spec/xoshiro256plus_spec.cr @@ -76,7 +76,7 @@ describe Random::XoShiRo256Plus do original.next_u.should eq(0xbf468782e4ab532b_u64) rng = original.split - rng.should_not be(original) - rng.next_u.should eq(0xef2817c89dfe32e1_u64) + rng.should_not eq(original) + rng.next_u.should eq(0x6ecba84e8c0ab44_u64) end end diff --git a/spec/xoshiro256starstar_spec.cr b/spec/xoshiro256starstar_spec.cr index e81a797..c76c6c9 100644 --- a/spec/xoshiro256starstar_spec.cr +++ b/spec/xoshiro256starstar_spec.cr @@ -76,7 +76,7 @@ describe Random::XoShiRo256StarStar do original.next_u.should eq(0xc5555444a74d7e83_u64) rng = original.split - rng.should_not be(original) - rng.next_u.should eq(0x228bb75bc497d835_u64) + rng.should_not eq(original) + rng.next_u.should eq(0x54f773200a4efa23_u64) end end diff --git a/src/splittable.cr b/src/splittable.cr index e5cb3a0..cf52a2a 100644 --- a/src/splittable.cr +++ b/src/splittable.cr @@ -14,8 +14,8 @@ class Random::Splittable private GOLDEN_GAMMA = 0x9e3779b97f4a7c15_u64 # odd - @seed : UInt64 - @gamma : UInt64 + protected setter seed : UInt64 + protected setter gamma : UInt64 def initialize s = default_gen.add(2_u64 &* GOLDEN_GAMMA) @@ -38,8 +38,9 @@ class Random::Splittable mix32(next_seed) end - def split : self - self.class.new(next_u, mix_gamma(next_seed)) + def split_internal(other : self) : Nil + other.seed = next_u + other.gamma = mix_gamma(next_seed) end private def next_seed : UInt64 diff --git a/src/splittable128.cr b/src/splittable128.cr index 65376b0..3e71bb3 100644 --- a/src/splittable128.cr +++ b/src/splittable128.cr @@ -11,8 +11,8 @@ class Random::Splittable128 GAMMA_PRIME = (1_u64 << 57) &- 13 # "Ginny" GAMMA_GAMMA = 0x00281e2dba6606f3_u64 - @seed_hi : UInt64 - @seed_lo : UInt64 + protected setter seed_hi : UInt64 + protected setter seed_lo : UInt64 @gamma_hi : UInt64 @gamma_lo : UInt64 @next_split : UInt64 @@ -26,6 +26,13 @@ class Random::Splittable128 end def initialize(@seed_hi = next_default_seed, @seed_lo = 0_u64, s : UInt64 = GAMMA_GAMMA) + @gamma_hi = 0_u64 + @gamma_lo = 0_u64 + @next_split = 0_u64 + mix_gamma(s) + end + + protected def mix_gamma(s) # we require 0 <= s <= Ginny s &+= GAMMA_GAMMA s &-= GAMMA_PRIME if s >= GAMMA_PRIME @@ -38,9 +45,11 @@ class Random::Splittable128 @next_split = s end - def split : self + def split_internal(other : self) : Nil next_raw64 - Splittable128.new(@seed_hi, @seed_lo, @next_split) + other.seed_hi = @seed_hi + other.seed_lo = @seed_lo + other.mix_gamma(@next_split) end def next_u : UInt64 diff --git a/src/xoshiro128.cr b/src/xoshiro128.cr index 379d683..941ea91 100644 --- a/src/xoshiro128.cr +++ b/src/xoshiro128.cr @@ -121,9 +121,9 @@ abstract class Random::XoShiRo128 @state.to_unsafe[3] = s3 end - # Returns a new instance that shares no mutable state with this instance. - def split + def split_internal(other : self) : Nil self.class.new(@state.map { |s| murmurhash3(s) }) + other.next_u end @[AlwaysInline] diff --git a/src/xoshiro256.cr b/src/xoshiro256.cr index 66a87af..2c0730c 100644 --- a/src/xoshiro256.cr +++ b/src/xoshiro256.cr @@ -110,12 +110,9 @@ abstract class Random::XoShiRo256 @state.to_unsafe[3] = s3 end - # Returns a new instance that shares no mutable state with this instance. The - # sequence generated by the new instance depends deterministically from the - # state of this instance, but the probability that the sequence generated by - # this instance and by the new instance overlap is negligible. - def split - self.class.new(@state.map { |s| murmurhash3(s) }) + def split_internal(other : self) : Nil + @state.map! { |s| murmurhash3(s) } + other.next_u end @[AlwaysInline]