use "random"
class ref Randomness
"""
Source of randomness, providing methods for generating uniformly distributed
values of the primitive numeric types.
The integer methods (`u8` through `isize`) generate values in the closed
interval [min, max]. Both bounds are included, so every value of the type can
be produced.
The floating-point methods (`f32` and `f64`) scale a value from the underlying
generator's `real()` (uniformly distributed in [0, 1)) onto the requested
range. `min` is always reachable and results are never below `min`, but `max`
is only an approximate upper bound: floating-point rounding means `max` may or
may not be produced, and an `f32` result can land marginally above `max`. Do
not rely on `max` being included or excluded.
"""
let _random: Random
new ref create(seed1: U64 = 42, seed2: U64 = 0) =>
_random = Rand(seed1, seed2)
fun ref u8(min: U8 = U8.min_value(), max: U8 = U8.max_value()): U8 =>
"""
Generate a U8 in closed interval [min, max]
(default: [min_value, max_value]).
Behavior is undefined if `min` > `max`.
"""
if (min == U8.min_value()) and (max == U8.max_value()) then
_random.u8()
else
min + _random.int((max - min).u64() + 1).u8()
end
fun ref u16(min: U16 = U16.min_value(), max: U16 = U16.max_value()): U16 =>
"""
Generate a U16 in closed interval [min, max]
(default: [min_value, max_value]).
Behavior is undefined if `min` > `max`.
"""
if (min == U16.min_value()) and (max == U16.max_value()) then
_random.u16()
else
min + _random.int((max - min).u64() + 1).u16()
end
fun ref u32(min: U32 = U32.min_value(), max: U32 = U32.max_value()): U32 =>
"""
Generate a U32 in closed interval [min, max]
(default: [min_value, max_value]).
Behavior is undefined if `min` > `max`.
"""
if (min == U32.min_value()) and (max == U32.max_value()) then
_random.u32()
else
min + _random.int((max - min).u64() + 1).u32()
end
fun ref u64(min: U64 = U64.min_value(), max: U64 = U64.max_value()): U64 =>
"""
Generate a U64 in closed interval [min, max]
(default: [min_value, max_value]).
Behavior is undefined if `min` > `max`.
"""
if (min == U64.min_value()) and (max == U64.max_value()) then
_random.u64()
elseif min > U32.max_value().u64() then
(u32((min >> 32).u32(), (max >> 32).u32()).u64() << 32) or _random.u32().u64()
elseif max > U32.max_value().u64() then
let high = (u32((min >> 32).u32(), (max >> 32).u32()).u64() << 32).u64()
let low =
if high > 0 then
_random.u32().u64()
else
u32(min.u32(), U32.max_value()).u64()
end
high or low
else
// range within U32 range
u32(min.u32(), max.u32()).u64()
end
fun ref u128(
min: U128 = U128.min_value(),
max: U128 = U128.max_value())
: U128
=>
"""
Generate a U128 in closed interval [min, max]
(default: [min_value, max_value]).
Behavior is undefined if `min` > `max`.
"""
if (min == U128.min_value()) and (max == U128.max_value()) then
_random.u128()
elseif min > U64.max_value().u128() then
// both above U64 range - chose random low 64 bits
(u64((min >> 64).u64(), (max >> 64).u64()).u128() << 64) or u64().u128()
elseif max > U64.max_value().u128() then
// min below U64 max value
let high = (u64((min >> 64).u64(), (max >> 64).u64()).u128() << 64)
let low =
if high > 0 then
// number will be bigger than U64 max anyway, so chose a random lower u64
u64().u128()
else
// number <= U64 max, so chose lower u64 while considering requested range min
u64(min.u64(), U64.max_value()).u128()
end
high or low
else
// range within u64 range
u64(min.u64(), max.u64()).u128()
end
fun ref ulong(
min: ULong = ULong.min_value(),
max: ULong = ULong.max_value())
: ULong
=>
"""
Generate a ULong in closed interval [min, max]
(default: [min_value, max_value]).
Behavior is undefined if `min` > `max`.
"""
u64(min.u64(), max.u64()).ulong()
fun ref usize(
min: USize = USize.min_value(),
max: USize = USize.max_value())
: USize
=>
"""
Generate a USize in closed interval [min, max]
(default: [min_value, max_value]).
Behavior is undefined if `min` > `max`.
"""
u64(min.u64(), max.u64()).usize()
fun ref i8(min: I8 = I8.min_value(), max: I8 = I8.max_value()): I8 =>
"""
Generate a I8 in closed interval [min, max]
(default: [min_value, max_value]).
Behavior is undefined if `min` > `max`.
"""
min + u8(0, (max - min).u8()).i8()
fun ref i16(min: I16 = I16.min_value(), max: I16 = I16.max_value()): I16 =>
"""
Generate a I16 in closed interval [min, max]
(default: [min_value, max_value]).
Behavior is undefined if `min` > `max`.
"""
min + u16(0, (max - min).u16()).i16()
fun ref i32(min: I32 = I32.min_value(), max: I32 = I32.max_value()): I32 =>
"""
Generate a I32 in closed interval [min, max]
(default: [min_value, max_value]).
Behavior is undefined if `min` > `max`.
"""
min + u32(0, (max - min).u32()).i32()
fun ref i64(min: I64 = I64.min_value(), max: I64 = I64.max_value()): I64 =>
"""
Generate a I64 in closed interval [min, max]
(default: [min_value, max_value]).
Behavior is undefined if `min` > `max`.
"""
min + u64(0, (max - min).u64()).i64()
fun ref i128(
min: I128 = I128.min_value(),
max: I128 = I128.max_value())
: I128
=>
"""
Generate a I128 in closed interval [min, max]
(default: [min_value, max_value]).
Behavior is undefined if `min` > `max`.
"""
min + u128(0, (max - min).u128()).i128()
fun ref ilong(
min: ILong = ILong.min_value(),
max: ILong = ILong.max_value())
: ILong
=>
"""
Generate a ILong in closed interval [min, max]
(default: [min_value, max_value]).
Behavior is undefined if `min` > `max`.
"""
min + ulong(0, (max - min).ulong()).ilong()
fun ref isize(
min: ISize = ISize.min_value(),
max: ISize = ISize.max_value())
: ISize
=>
"""
Generate a ISize in closed interval [min, max]
(default: [min_value, max_value]).
Behavior is undefined if `min` > `max`.
"""
min + usize(0, (max - min).usize()).isize()
fun ref f32(min: F32 = 0.0, max: F32 = 1.0): F32 =>
"""
Generate an F32 in the range from `min` to `max` (default: 0.0 to 1.0).
`min` is always reachable. On the default range the result is the closed
interval [0.0, 1.0]: `real()`'s largest value rounds up to 1.0 when
converted to F32, so `max` is produced when that top value is drawn. See
`Randomness` for how `max` behaves on other ranges.
"""
(_random.real().f32() * (max-min)) + min
fun ref f64(min: F64 = 0.0, max: F64 = 1.0): F64 =>
"""
Generate an F64 in the range from `min` to `max` (default: 0.0 to 1.0).
`min` is always reachable. On the default range the result is the half-open
interval [0.0, 1.0); `max` (1.0) is never produced. See `Randomness` for how
`max` behaves on other ranges.
"""
(_random.real() * (max-min)) + min
fun ref bool(): Bool =>
"""
Generate a random Bool value.
"""
(_random.next() % 2) == 0
fun ref shuffle[T](array: Array[T] ref) =>
"""
Shuffle the elements of the array into a random order, mutating the array.
"""
_random.shuffle[T](array)