Reproducible random numbers

← Guest standard library support

Status: Supported in the current checkout, in stdlib:core 1.16.0. Import kotlin.random.*. The API follows Kotlin Random for the explicitly listed signatures. Collection random, shuffle and shuffled are not part of this addition.

import kotlin.random.*

fun main() {
    val seeded = Random(42)
    val die = seeded.nextInt(1, 7)
    val unit = seeded.nextDouble()
    val bytes = seeded.nextBytes(16)
    val inclusive = Random.nextUInt(1u..6u)
}

Executable surface

Random is an abstract class with nextBits(bitCount: Int): Int. Guest subclasses can implement it and inherit or override the open signed, floating and byte methods. Random(seed: Int) and Random(seed: Long) create independent sources; Int seeds sign-extend to Long.

API Bounds and result
nextBits(Int) Low 0..32 bits filled, upper bits zero; 32 bits may form a negative Int
nextInt(), nextLong() Full signed domain
nextInt(until), nextLong(until) [0, until)
nextInt(from, until), nextLong(from, until) [from, until) including widths that overflow signed subtraction
nextInt(IntRange), nextLong(LongRange) Inclusive, including the full signed domain
nextBoolean() One random bit
nextFloat(), nextDouble() [0, 1) with 24 and 53 random fractional bits
nextDouble(until), nextDouble(from, until) Finite increasing bounds, exclusive upper endpoint
nextBytes(ByteArray), nextBytes(size: Int) Fill the supplied array or allocate and fill a new one
nextBytes(ByteArray, fromIndex: Int, toIndex: Int) Fill exactly [fromIndex, toIndex) and return the same array
nextUInt, nextULong extensions Full unsigned domain, until, from/until, and inclusive range overloads
nextUBytes extensions UByteArray, size, and explicit three-argument subrange overloads

Byte subrange overloads require both index arguments; arbitrary omitted-index defaults are not exposed. Integer bounds use rejection sampling before reduction, avoiding modulo bias. Rejection loops consume instruction quota as ordinary Guest loops; there is no fixed instruction cost per bounded draw. Floating results round down from the upper endpoint when necessary, including adjacent representable bounds and finite ranges whose width overflows Double. Invalid bounds, empty inclusive ranges, invalid bit counts, and byte index ranges throw IllegalArgumentException before consuming state or modifying an array. Negative allocation sizes use the existing NegativeArraySizeException behavior.

State and reproducibility

Random.Default is the companion object, also accessible as Random. It owns one source seeded with 0L per program/session. Aliases and cooperative tasks share it; draw order determines which task receives which value. Starting a fresh program restarts this fixed sequence. There is no clock or host-entropy input. Use independent seeded sources when task scheduling must not influence a particular sequence.

The seeded generator uses SplitMix64: increment a wrapping Long state by 0x9e3779b97f4a7c15, mix with unsigned shifts 30/27/31 and multipliers 0xbf58476d1ce4e5b9 / 0x94d049bb133111eb, and take the requested high bits into the low result bits. nextBits(0) does not advance state. A full Int consumes one word; a Long concatenates two 32-bit draws. Float consumes one 24-bit draw; Double concatenates 26 and 27 bits. Each filled byte consumes one 8-bit draw. Bounded draws may reject and consume more words. Empty byte fills consume none. These consumption rules make Compukters sequences reproducible; they do not match Kotlin/JVM Random. Future algorithm changes require an explicit library contract/version decision.

Generator objects and Default state are managed Guest heap data. They retain state across quota slices, GC and computer checkpoints without a host capability or new persistence encoding. Generator/array allocations and arithmetic use existing VM heap and instruction quotas. This is a pseudorandom source for simulations and gameplay, not cryptography.

Evidence and compatibility

MinimalScriptLoweringTest, test random compiles reproducible generators ranges and stateful dispatch, compiles the resource modules/common/compiler-k2/src/test/resources/kotlin/random/main.kt twice and checks deterministic artifact bytes. testKotlinRandomVmConformance executes independent known-answer vectors/hashes, scripted rejection sources, signed/unsigned extreme ranges, floating endpoint correction, byte mutation/identity/errors, factory independence, Default aliases, subclass dispatch and method references at budgets 128 and 512. Its Rust random.rs harness also restores a mid-execution checkpoint for both budgets and compares continued execution with the original computer.

DiagnosticQueryTest, test random generators and extensions resolve with source and metadata inputs, checks IDE diagnostics with and without attached platform sources. PlatformMetadataCompilerTest, test abstract platform methods and accessors retain linkable dispatch slots, protects abstract library members.

This additive library version changes module content identities and dependent generated metadata. Recompile dependent platform modules/programs. Platform bundle/module formats, worker protocols, Runtime ABI and native transport/persistence schemas are unchanged; random code uses existing arithmetic, managed classes and math instructions. ABI reference owns those boundaries.