discard byte order preservation

pull/13608/head
Subhomoy Haldar 2022-02-28 12:53:52 +05:30
parent 878ad17c9b
commit 35e9f229c3
11 changed files with 44 additions and 389 deletions

View File

@ -94,52 +94,29 @@ pub fn (mut rng MT19937RNG) seed(seed_data []u32) {
// byte returns a uniformly distributed pseudorandom 8-bit unsigned positive `byte`.
[inline]
pub fn (mut rng MT19937RNG) byte() byte {
// Can we extract a value from the buffer?
if rng.bytes_left >= 1 {
rng.bytes_left -= 1
value := byte(rng.buffer)
rng.buffer >>= 8
return value
}
// Add a new value to the buffer
rng.buffer = rng.internal_u64()
rng.buffer = rng.u64()
rng.bytes_left = 7
value := byte(rng.buffer)
rng.buffer >>= 8
return value
}
[inline]
fn (mut rng MT19937RNG) step_by(amount int) u64 {
next_number := rng.internal_u64()
bits_left := rng.bytes_left * 8
bits_needed := amount - bits_left
old_value := rng.buffer & ((u64(1) << bits_left) - 1)
new_value := next_number & ((u64(1) << bits_needed) - 1)
value := old_value | (new_value << bits_left)
rng.buffer = next_number >> bits_needed
rng.bytes_left = 8 - (bits_needed / 8)
return value
}
// u16 returns a pseudorandom 16bit int in range `[0, 2¹)`.
[inline]
pub fn (mut rng MT19937RNG) u16() u16 {
// Can we take a whole u16 out of the buffer?
if rng.bytes_left >= 2 {
rng.bytes_left -= 2
value := u16(rng.buffer)
rng.buffer >>= 16
return value
}
if rng.bytes_left > 0 {
return u16(rng.step_by(16))
}
ans := rng.internal_u64()
ans := rng.u64()
rng.buffer = ans >> 16
rng.bytes_left = 6
return u16(ans)
@ -155,11 +132,7 @@ pub fn (mut rng MT19937RNG) u32() u32 {
rng.buffer >>= 32
return value
}
if rng.bytes_left > 0 {
return u32(rng.step_by(32))
}
// We're out so we start fresh.
ans := rng.internal_u64()
ans := rng.u64()
rng.buffer = ans >> 32
rng.bytes_left = 4
return u32(ans)
@ -168,14 +141,6 @@ pub fn (mut rng MT19937RNG) u32() u32 {
// u64 returns a pseudorandom 64bit int in range `[0, 2)`.
[inline]
pub fn (mut rng MT19937RNG) u64() u64 {
if rng.bytes_left > 0 {
return rng.step_by(64)
}
return rng.internal_u64()
}
[inline]
fn (mut rng MT19937RNG) internal_u64() u64 {
mag01 := [u64(0), u64(mt19937.matrix_a)]
mut x := u64(0)
mut i := int(0)
@ -202,6 +167,7 @@ fn (mut rng MT19937RNG) internal_u64() u64 {
return x
}
// block_size returns the number of bits that the RNG can produce in a single iteration.
[inline]
pub fn (mut rng MT19937RNG) block_size() int {
return 64

View File

@ -330,43 +330,3 @@ fn test_mt19937_f64_in_range() {
}
}
}
fn test_mt19937_buffering() {
for seed in seeds {
for offset in [0, 2, 3, 5, 19, 47] {
count := 5
mut rngs := []rand.PRNG{cap: count}
for i in 0 .. count {
rngs << &rand.PRNG(&mt19937.MT19937RNG{})
rngs[i].seed(seed)
}
for mut rng in rngs {
for _ in 0 .. offset {
rng.byte()
}
}
for _ in 0 .. 6 {
first_64bit := rngs[0].u64()
second_64bit := u64(rngs[1].u32()) | (u64(rngs[1].u32()) << 32)
mut third_64bit := u64(rngs[2].byte())
for shift in 1 .. 8 {
third_64bit |= u64(rngs[2].byte()) << (shift * 8)
}
fourth_64bit := u64(rngs[3].byte()) | (u64(rngs[3].u32()) << 8) | (u64(rngs[3].u16()) << 40) | (u64(rngs[3].byte()) << 56)
eight_bytes := rngs[4].bytes(8) or { panic("Couldn't obtain random bytes") }
mut fifth_64bit := u64(eight_bytes[0]) | (u64(eight_bytes[1]) << 8) | (u64(eight_bytes[2]) << 16) | (u64(eight_bytes[3]) << 24) | (u64(eight_bytes[4]) << 32) | (u64(eight_bytes[5]) << 40) | (u64(eight_bytes[6]) << 48) | (u64(eight_bytes[7]) << 56)
assert first_64bit == second_64bit
assert first_64bit == third_64bit
assert first_64bit == fourth_64bit
assert first_64bit == fifth_64bit
}
}
}
}

View File

@ -31,66 +31,34 @@ pub fn (mut rng MuslRNG) seed(seed_data []u32) {
// byte returns a uniformly distributed pseudorandom 8-bit unsigned positive `byte`.
[inline]
fn (mut rng MuslRNG) byte() byte {
// Can we extract a value from the buffer?
if rng.bytes_left >= 1 {
rng.bytes_left -= 1
value := byte(rng.buffer)
rng.buffer >>= 8
return value
}
// Add a new value to the buffer
rng.buffer = rng.internal_u32()
rng.buffer = rng.u32()
rng.bytes_left = 3
value := byte(rng.buffer)
rng.buffer >>= 8
return value
}
[inline]
fn (mut rng MuslRNG) step_by(amount int) u32 {
next_number := rng.internal_u32()
bits_left := rng.bytes_left * 8
bits_needed := amount - bits_left
old_value := rng.buffer & ((u32(1) << bits_left) - 1)
new_value := next_number & ((u32(1) << bits_needed) - 1)
value := old_value | (new_value << bits_left)
rng.buffer = next_number >> bits_needed
rng.bytes_left = 4 - (bits_needed / 8)
return value
}
// u16 returns a pseudorandom 16-bit unsigned integer (`u16`).
[inline]
pub fn (mut rng MuslRNG) u16() u16 {
// Can we take a whole u16 out of the buffer?
if rng.bytes_left >= 2 {
rng.bytes_left -= 2
value := u16(rng.buffer)
rng.buffer >>= 16
return value
}
if rng.bytes_left > 0 {
return u16(rng.step_by(16))
}
ans := rng.internal_u32()
ans := rng.u32()
rng.buffer = ans >> 16
rng.bytes_left = 2
return u16(ans)
}
// u32 returns a pseudorandom 32-bit unsigned integer (`u32`).
[inline]
pub fn (mut rng MuslRNG) u32() u32 {
if rng.bytes_left >= 1 {
return rng.step_by(32)
}
return rng.internal_u32()
}
// temper returns a tempered value based on `prev` value.
[inline]
fn temper(prev u32) u32 {
@ -102,7 +70,8 @@ fn temper(prev u32) u32 {
return x
}
fn (mut rng MuslRNG) internal_u32() u32 {
// u32 returns a pseudorandom 32-bit unsigned integer (`u32`).
fn (mut rng MuslRNG) u32() u32 {
rng.state = rng.state * 1103515245 + 12345
// We are not dividing by 2 (or shifting right by 1)
// because we want all 32-bits of random data
@ -115,6 +84,7 @@ pub fn (mut rng MuslRNG) u64() u64 {
return u64(rng.u32()) | (u64(rng.u32()) << 32)
}
// block_size returns the number of bits that the RNG can produce in a single iteration.
[inline]
pub fn (mut rng MuslRNG) block_size() int {
return 32

View File

@ -319,44 +319,3 @@ fn test_musl_f64_in_range() {
}
}
}
fn test_musl_buffering() {
for seed in seeds {
for offset in [0, 2, 3, 5, 19, 47] {
count := 5
mut rngs := []rand.PRNG{cap: count}
for i in 0 .. count {
rngs << &rand.PRNG(&musl.MuslRNG{})
rngs[i].seed(seed)
}
for mut rng in rngs {
for _ in 0 .. offset {
rng.byte()
}
}
for _ in 0 .. 6 {
first_64bit := rngs[0].u64()
second_64bit := u64(rngs[1].u32()) | (u64(rngs[1].u32()) << 32)
mut third_64bit := u64(rngs[2].byte())
for shift in 1 .. 8 {
third_64bit |= u64(rngs[2].byte()) << (shift * 8)
}
fourth_64bit := u64(rngs[3].byte()) | (u64(rngs[3].u32()) << 8) | (u64(rngs[3].u16()) << 40) | (u64(rngs[3].byte()) << 56)
eight_bytes := rngs[4].bytes(8) or { panic("Couldn't obtain random bytes") }
mut fifth_64bit := u64(eight_bytes[0]) | (u64(eight_bytes[1]) << 8) | (u64(eight_bytes[2]) << 16) | (u64(eight_bytes[3]) << 24) | (u64(eight_bytes[4]) << 32) | (u64(eight_bytes[5]) << 40) | (u64(eight_bytes[6]) << 48) | (u64(eight_bytes[7]) << 56)
println('${first_64bit:x}, ${fourth_64bit:x}')
assert first_64bit == second_64bit
assert first_64bit == third_64bit
assert first_64bit == fourth_64bit
assert first_64bit == fifth_64bit
}
}
}
}

View File

@ -40,52 +40,29 @@ pub fn (mut rng PCG32RNG) seed(seed_data []u32) {
// byte returns a uniformly distributed pseudorandom 8-bit unsigned positive `byte`.
[inline]
fn (mut rng PCG32RNG) byte() byte {
// Can we extract a value from the buffer?
if rng.bytes_left >= 1 {
rng.bytes_left -= 1
value := byte(rng.buffer)
rng.buffer >>= 8
return value
}
// Add a new value to the buffer
rng.buffer = rng.internal_u32()
rng.buffer = rng.u32()
rng.bytes_left = 3
value := byte(rng.buffer)
rng.buffer >>= 8
return value
}
[inline]
fn (mut rng PCG32RNG) step_by(amount int) u32 {
next_number := rng.internal_u32()
bits_left := rng.bytes_left * 8
bits_needed := amount - bits_left
old_value := rng.buffer & ((u32(1) << bits_left) - 1)
new_value := next_number & ((u32(1) << bits_needed) - 1)
value := old_value | (new_value << bits_left)
rng.buffer = next_number >> bits_needed
rng.bytes_left = 4 - (bits_needed / 8)
return value
}
// u16 returns a pseudorandom 16-bit unsigned integer (`u16`).
[inline]
pub fn (mut rng PCG32RNG) u16() u16 {
// Can we take a whole u16 out of the buffer?
if rng.bytes_left >= 2 {
rng.bytes_left -= 2
value := u16(rng.buffer)
rng.buffer >>= 16
return value
}
if rng.bytes_left > 0 {
return u16(rng.step_by(16))
}
ans := rng.internal_u32()
ans := rng.u32()
rng.buffer = ans >> 16
rng.bytes_left = 2
return u16(ans)
@ -93,14 +70,7 @@ pub fn (mut rng PCG32RNG) u16() u16 {
// u32 returns a pseudorandom unsigned `u32`.
[inline]
pub fn (mut rng PCG32RNG) u32() u32 {
if rng.bytes_left >= 1 {
return rng.step_by(32)
}
return rng.internal_u32()
}
fn (mut rng PCG32RNG) internal_u32() u32 {
fn (mut rng PCG32RNG) u32() u32 {
oldstate := rng.state
rng.state = oldstate * (6364136223846793005) + rng.inc
xorshifted := u32(((oldstate >> u64(18)) ^ oldstate) >> u64(27))
@ -114,6 +84,7 @@ pub fn (mut rng PCG32RNG) u64() u64 {
return u64(rng.u32()) | (u64(rng.u32()) << 32)
}
// block_size returns the number of bits that the RNG can produce in a single iteration.
[inline]
pub fn (mut rng PCG32RNG) block_size() int {
return 32

View File

@ -326,44 +326,3 @@ fn test_pcg32_f64_in_range() {
fn test_change_default_random_generator() {
rand.set_rng(&rand.PRNG(&pcg32.PCG32RNG{}))
}
fn test_pcg32_buffering() {
for seed in seeds {
for offset in [0, 2, 3, 5, 19, 47] {
count := 5
mut rngs := []rand.PRNG{cap: count}
for i in 0 .. count {
rngs << &rand.PRNG(&pcg32.PCG32RNG{})
rngs[i].seed(seed)
}
for mut rng in rngs {
for _ in 0 .. offset {
rng.byte()
}
}
for _ in 0 .. 6 {
first_64bit := rngs[0].u64()
second_64bit := u64(rngs[1].u32()) | (u64(rngs[1].u32()) << 32)
mut third_64bit := u64(rngs[2].byte())
for shift in 1 .. 8 {
third_64bit |= u64(rngs[2].byte()) << (shift * 8)
}
fourth_64bit := u64(rngs[3].byte()) | (u64(rngs[3].u32()) << 8) | (u64(rngs[3].u16()) << 40) | (u64(rngs[3].byte()) << 56)
eight_bytes := rngs[4].bytes(8) or { panic("Couldn't obtain random bytes") }
mut fifth_64bit := u64(eight_bytes[0]) | (u64(eight_bytes[1]) << 8) | (u64(eight_bytes[2]) << 16) | (u64(eight_bytes[3]) << 24) | (u64(eight_bytes[4]) << 32) | (u64(eight_bytes[5]) << 40) | (u64(eight_bytes[6]) << 48) | (u64(eight_bytes[7]) << 56)
println('${first_64bit:x}, ${fourth_64bit:x}')
assert first_64bit == second_64bit
assert first_64bit == third_64bit
assert first_64bit == fourth_64bit
assert first_64bit == fifth_64bit
}
}
}
}

View File

@ -30,52 +30,29 @@ pub fn (mut rng SplitMix64RNG) seed(seed_data []u32) {
// byte returns a uniformly distributed pseudorandom 8-bit unsigned positive `byte`.
[inline]
pub fn (mut rng SplitMix64RNG) byte() byte {
// Can we extract a value from the buffer?
if rng.bytes_left >= 1 {
rng.bytes_left -= 1
value := byte(rng.buffer)
rng.buffer >>= 8
return value
}
// Add a new value to the buffer
rng.buffer = rng.internal_u64()
rng.buffer = rng.u64()
rng.bytes_left = 7
value := byte(rng.buffer)
rng.buffer >>= 8
return value
}
[inline]
fn (mut rng SplitMix64RNG) step_by(amount int) u64 {
next_number := rng.internal_u64()
bits_left := rng.bytes_left * 8
bits_needed := amount - bits_left
old_value := rng.buffer & ((u64(1) << bits_left) - 1)
new_value := next_number & ((u64(1) << bits_needed) - 1)
value := old_value | (new_value << bits_left)
rng.buffer = next_number >> bits_needed
rng.bytes_left = 8 - (bits_needed / 8)
return value
}
// u16 returns a pseudorandom 16bit int in range `[0, 2¹)`.
[inline]
pub fn (mut rng SplitMix64RNG) u16() u16 {
// Can we take a whole u16 out of the buffer?
if rng.bytes_left >= 2 {
rng.bytes_left -= 2
value := u16(rng.buffer)
rng.buffer >>= 16
return value
}
if rng.bytes_left > 0 {
return u16(rng.step_by(16))
}
ans := rng.internal_u64()
ans := rng.u64()
rng.buffer = ans >> 16
rng.bytes_left = 6
return u16(ans)
@ -84,18 +61,13 @@ pub fn (mut rng SplitMix64RNG) u16() u16 {
// u32 returns a pseudorandom 32bit int in range `[0, 2³²)`.
[inline]
pub fn (mut rng SplitMix64RNG) u32() u32 {
// Can we take a whole u32 out of the buffer?
if rng.bytes_left >= 4 {
rng.bytes_left -= 4
value := u32(rng.buffer)
rng.buffer >>= 32
return value
}
if rng.bytes_left > 0 {
return u32(rng.step_by(32))
}
// We're out so we start fresh.
ans := rng.internal_u64()
ans := rng.u64()
rng.buffer = ans >> 32
rng.bytes_left = 4
return u32(ans)
@ -104,15 +76,6 @@ pub fn (mut rng SplitMix64RNG) u32() u32 {
// u64 returns a pseudorandom 64bit int in range `[0, 2)`.
[inline]
pub fn (mut rng SplitMix64RNG) u64() u64 {
if rng.bytes_left > 0 {
return rng.step_by(64)
}
return rng.internal_u64()
}
// u64 updates the PRNG state and returns the next pseudorandom `u64`.
[inline]
fn (mut rng SplitMix64RNG) internal_u64() u64 {
rng.state += (0x9e3779b97f4a7c15)
mut z := rng.state
z = (z ^ (z >> u64(30))) * 0xbf58476d1ce4e5b9
@ -120,6 +83,7 @@ fn (mut rng SplitMix64RNG) internal_u64() u64 {
return z ^ (z >> (31))
}
// block_size returns the number of bits that the RNG can produce in a single iteration.
[inline]
pub fn (mut rng SplitMix64RNG) block_size() int {
return 64

View File

@ -319,43 +319,3 @@ fn test_splitmix64_f64_in_range() {
}
}
}
fn test_splitmix64_buffering() {
for seed in seeds {
for offset in [0, 2, 3, 5, 19, 47] {
count := 5
mut rngs := []rand.PRNG{cap: count}
for i in 0 .. count {
rngs << &rand.PRNG(&splitmix64.SplitMix64RNG{})
rngs[i].seed(seed)
}
for mut rng in rngs {
for _ in 0 .. offset {
rng.byte()
}
}
for _ in 0 .. 6 {
first_64bit := rngs[0].u64()
second_64bit := u64(rngs[1].u32()) | (u64(rngs[1].u32()) << 32)
mut third_64bit := u64(rngs[2].byte())
for shift in 1 .. 8 {
third_64bit |= u64(rngs[2].byte()) << (shift * 8)
}
fourth_64bit := u64(rngs[3].byte()) | (u64(rngs[3].u32()) << 8) | (u64(rngs[3].u16()) << 40) | (u64(rngs[3].byte()) << 56)
eight_bytes := rngs[4].bytes(8) or { panic("Couldn't obtain random bytes") }
mut fifth_64bit := u64(eight_bytes[0]) | (u64(eight_bytes[1]) << 8) | (u64(eight_bytes[2]) << 16) | (u64(eight_bytes[3]) << 24) | (u64(eight_bytes[4]) << 32) | (u64(eight_bytes[5]) << 40) | (u64(eight_bytes[6]) << 48) | (u64(eight_bytes[7]) << 56)
assert first_64bit == second_64bit
assert first_64bit == third_64bit
assert first_64bit == fourth_64bit
assert first_64bit == fifth_64bit
}
}
}
}

View File

@ -37,7 +37,9 @@ fn calculate_iterations_for(bits int) int {
// SysRNG is the PRNG provided by default in the libc implementiation that V uses.
pub struct SysRNG {
mut:
seed u32 = seed.time_seed_32()
seed u32 = seed.time_seed_32()
buffer int
bytes_left int
}
// r.seed() sets the seed of the accepting SysRNG to the given data.
@ -62,13 +64,29 @@ pub fn (r SysRNG) default_rand() int {
// byte returns a uniformly distributed pseudorandom 8-bit unsigned positive `byte`.
[inline]
pub fn (r SysRNG) byte() byte {
return byte(C.rand())
pub fn (mut r SysRNG) byte() byte {
if r.bytes_left >= 1 {
r.bytes_left -= 1
value := byte(r.buffer)
r.buffer >>= 8
return value
}
r.buffer = r.default_rand()
r.bytes_left = sys.rand_bytesize - 1
value := byte(r.buffer)
r.buffer >>= 8
return value
}
// u16 returns a uniformly distributed pseudorandom 16-bit unsigned positive `u16`.
[inline]
pub fn (r SysRNG) u16() u16 {
pub fn (mut r SysRNG) u16() u16 {
if r.bytes_left >= 2 {
r.bytes_left -= 2
value := u16(r.buffer)
r.buffer >>= 16
return value
}
mut result := u16(C.rand())
for i in 1 .. sys.u16_iter_count {
result = result ^ (u16(C.rand()) << (sys.rand_bitsize * i))
@ -96,6 +114,7 @@ pub fn (r SysRNG) u64() u64 {
return result
}
// block_size returns the number of bits that the RNG can produce in a single iteration.
[inline]
pub fn (r SysRNG) block_size() int {
return sys.rand_bitsize

View File

@ -42,44 +42,23 @@ pub fn (mut rng WyRandRNG) byte() byte {
return value
}
// Add a new value to the buffer
rng.buffer = rng.internal_u64()
rng.buffer = rng.u64()
rng.bytes_left = 7
value := byte(rng.buffer)
rng.buffer >>= 8
return value
}
[inline]
fn (mut rng WyRandRNG) step_by(amount int) u64 {
next_number := rng.internal_u64()
bits_left := rng.bytes_left * 8
bits_needed := amount - bits_left
old_value := rng.buffer & ((u64(1) << bits_left) - 1)
new_value := next_number & ((u64(1) << bits_needed) - 1)
value := old_value | (new_value << bits_left)
rng.buffer = next_number >> bits_needed
rng.bytes_left = 8 - (bits_needed / 8)
return value
}
// u16 returns a pseudorandom 16bit int in range `[0, 2¹)`.
[inline]
pub fn (mut rng WyRandRNG) u16() u16 {
// Can we take a whole u16 out of the buffer?
if rng.bytes_left >= 2 {
rng.bytes_left -= 2
value := u16(rng.buffer)
rng.buffer >>= 16
return value
}
if rng.bytes_left > 0 {
return u16(rng.step_by(16))
}
ans := rng.internal_u64()
ans := rng.u64()
rng.buffer = ans >> 16
rng.bytes_left = 6
return u16(ans)
@ -88,18 +67,13 @@ pub fn (mut rng WyRandRNG) u16() u16 {
// u32 returns a pseudorandom 32bit int in range `[0, 2³²)`.
[inline]
pub fn (mut rng WyRandRNG) u32() u32 {
// Can we take a whole u32 out of the buffer?
if rng.bytes_left >= 4 {
rng.bytes_left -= 4
value := u32(rng.buffer)
rng.buffer >>= 32
return value
}
if rng.bytes_left > 0 {
return u32(rng.step_by(32))
}
// We're out so we start fresh.
ans := rng.internal_u64()
ans := rng.u64()
rng.buffer = ans >> 32
rng.bytes_left = 4
return u32(ans)
@ -108,14 +82,6 @@ pub fn (mut rng WyRandRNG) u32() u32 {
// u64 returns a pseudorandom 64bit int in range `[0, 2)`.
[inline]
pub fn (mut rng WyRandRNG) u64() u64 {
if rng.bytes_left > 0 {
return rng.step_by(64)
}
return rng.internal_u64()
}
[inline]
fn (mut rng WyRandRNG) internal_u64() u64 {
unsafe {
mut seed1 := rng.state
seed1 += wyrand.wyp0
@ -125,6 +91,7 @@ fn (mut rng WyRandRNG) internal_u64() u64 {
return 0
}
// block_size returns the number of bits that the RNG can produce in a single iteration.
[inline]
pub fn (mut rng WyRandRNG) block_size() int {
return 64

View File

@ -319,43 +319,3 @@ fn test_wyrand_f64_in_range() {
}
}
}
fn test_wyrand_buffering() {
for seed in seeds {
for offset in [0, 2, 3, 5, 19, 47] {
count := 5
mut rngs := []rand.PRNG{cap: count}
for i in 0 .. count {
rngs << &rand.PRNG(&wyrand.WyRandRNG{})
rngs[i].seed(seed)
}
for mut rng in rngs {
for _ in 0 .. offset {
rng.byte()
}
}
for _ in 0 .. 6 {
first_64bit := rngs[0].u64()
second_64bit := u64(rngs[1].u32()) | (u64(rngs[1].u32()) << 32)
mut third_64bit := u64(rngs[2].byte())
for shift in 1 .. 8 {
third_64bit |= u64(rngs[2].byte()) << (shift * 8)
}
fourth_64bit := u64(rngs[3].byte()) | (u64(rngs[3].u32()) << 8) | (u64(rngs[3].u16()) << 40) | (u64(rngs[3].byte()) << 56)
eight_bytes := rngs[4].bytes(8) or { panic("Couldn't obtain random bytes") }
mut fifth_64bit := u64(eight_bytes[0]) | (u64(eight_bytes[1]) << 8) | (u64(eight_bytes[2]) << 16) | (u64(eight_bytes[3]) << 24) | (u64(eight_bytes[4]) << 32) | (u64(eight_bytes[5]) << 40) | (u64(eight_bytes[6]) << 48) | (u64(eight_bytes[7]) << 56)
assert first_64bit == second_64bit
assert first_64bit == third_64bit
assert first_64bit == fourth_64bit
assert first_64bit == fifth_64bit
}
}
}
}