diff --git a/vlib/rand/rand.v b/vlib/rand/rand.v index ae4ba23daf6481..3719de57c619c4 100644 --- a/vlib/rand/rand.v +++ b/vlib/rand/rand.v @@ -42,7 +42,13 @@ pub fn (mut rng PRNG) read(mut buf []u8) { read_internal(mut rng, mut buf) } -// u32n returns a uniformly distributed pseudorandom 32-bit signed positive `u32` in range `[0, max)`. +// i32n returns a uniformly distributed pseudorandom 32-bit signed positive `i32` in range `[0, max)`. +@[inline] +pub fn (mut rng PRNG) i32n(max i32) !i32 { + return i32(rng.intn(max)!) +} + +// u32n returns a uniformly distributed pseudorandom 32-bit unsigned positive `u32` in range `[0, max)`. @[inline] pub fn (mut rng PRNG) u32n(max u32) !u32 { if max == 0 { @@ -138,6 +144,12 @@ pub fn (mut rng PRNG) i16() i16 { return i16(rng.u16()) } +// i32 returns a (possibly negative) pseudorandom 32-bit `i32`. +@[inline] +pub fn (mut rng PRNG) i32() i32 { + return i32(rng.u32()) +} + // int returns a (possibly negative) pseudorandom 32-bit `int`. @[inline] pub fn (mut rng PRNG) int() int { @@ -190,6 +202,16 @@ pub fn (mut rng PRNG) int_in_range(min int, max int) !int { return min + rng.intn(max - min)! } +// int_in_range returns a pseudorandom `int` in range `[min, max)`. +@[inline] +pub fn (mut rng PRNG) i32_in_range(min i32, max i32) !i32 { + if max <= min { + return error('max must be greater than min') + } + // This supports negative ranges like [-10, -5) because the difference is positive + return min + i32(rng.intn(max - min)!) +} + // i64_in_range returns a pseudorandom `i64` in range `[min, max)`. @[inline] pub fn (mut rng PRNG) i64_in_range(min i64, max i64) !i64 { @@ -564,11 +586,21 @@ pub fn i16() i16 { return default_rng.i16() } +// i32 returns a uniformly distributed pseudorandom 32-bit signed (possibly negative) `i32`. +pub fn i32() i32 { + return default_rng.i32() +} + // int returns a uniformly distributed pseudorandom 32-bit signed (possibly negative) `int`. pub fn int() int { return default_rng.int() } +// i32n returns a uniformly distributed pseudorandom 32-bit signed positive `i32` in range `[0, max)`. +pub fn i32n(max i32) !i32 { + return default_rng.i32n(max) +} + // intn returns a uniformly distributed pseudorandom 32-bit signed positive `int` in range `[0, max)`. pub fn intn(max int) !int { return default_rng.intn(max) @@ -580,6 +612,12 @@ pub fn int_in_range(min int, max int) !int { return default_rng.int_in_range(min, max) } +// int_in_range returns a uniformly distributed pseudorandom 32-bit signed int in range `[min, max)`. +// Both `min` and `max` can be negative, but we must have `min < max`. +pub fn i32_in_range(min i32, max i32) !i32 { + return default_rng.i32_in_range(min, max) +} + // int31 returns a uniformly distributed pseudorandom 31-bit signed positive `int`. pub fn int31() int { return default_rng.int31() diff --git a/vlib/rand/random_numbers_test.v b/vlib/rand/random_numbers_test.v index 3cca1916b8bcca..74a6bbe86f1f26 100644 --- a/vlib/rand/random_numbers_test.v +++ b/vlib/rand/random_numbers_test.v @@ -71,6 +71,15 @@ fn test_rand_intn() { } } +fn test_rand_i32n() { + max := i32(2525642) + for _ in 0 .. rnd_count { + value := rand.i32n(max) or { panic("Couldn't obtain i32") } + assert value >= 0 + assert value < max + } +} + fn test_rand_i64n() { max := i64(3246727724653636) for _ in 0 .. rnd_count { @@ -90,6 +99,16 @@ fn test_rand_int_in_range() { } } +fn test_rand_i32_in_range() { + min := i32(-4252) + max := i32(23054962) + for _ in 0 .. rnd_count { + value := rand.i32_in_range(min, max) or { panic("Couldn't obtain i32 in range") } + assert value >= min + assert value < max + } +} + fn test_rand_i64_in_range() { min := i64(-24095) max := i64(324058) @@ -324,7 +343,9 @@ fn test_rand_ascii() { fn ensure_same_output(mut rng rand.PRNG) { for _ in 0 .. 100 { assert rand.int() == rng.int() + assert rand.i32() == rng.i32() assert rand.intn(45) or { 0 } == rng.intn(45) or { 0 } + assert rand.i32n(45) or { 0 } == rng.i32n(45) or { 0 } assert rand.u64() == rng.u64() assert rand.f64() == rng.f64() assert rand.u32n(25) or { 0 } == rng.u32n(25) or { 0 } diff --git a/vlib/rand/sys/system_rng_test.v b/vlib/rand/sys/system_rng_test.v index 3a4fb3aea95480..54a4e72ba98aeb 100644 --- a/vlib/rand/sys/system_rng_test.v +++ b/vlib/rand/sys/system_rng_test.v @@ -178,6 +178,20 @@ fn test_sys_rng_intn() { } } +fn test_sys_rng_i32n() { + max := i32(2525642) + for seed in seeds { + seed_data := [seed] + mut rng := &rand.PRNG(&sys.SysRNG{}) + rng.seed(seed_data) + for _ in 0 .. range_limit { + value := rng.i32n(max) or { panic("Couldn't obtain i32") } + assert value >= 0 + assert value < max + } + } +} + fn test_sys_rng_i64n() { max := i64(3246727724653636) for seed in seeds { @@ -207,6 +221,21 @@ fn test_sys_rng_int_in_range() { } } +fn test_sys_rng_i32_in_range() { + min := i32(-4252) + max := i32(23054962) + for seed in seeds { + seed_data := [seed] + mut rng := &rand.PRNG(&sys.SysRNG{}) + rng.seed(seed_data) + for _ in 0 .. range_limit { + value := rng.i32_in_range(min, max) or { panic("Couldn't obtain i32 in range") } + assert value >= min + assert value < max + } + } +} + fn test_sys_rng_i64_in_range() { min := i64(-24095) max := i64(324058)