Provide Xoshiro256**, Xoshiro256++ and LCG64 PRNGs

This commit is contained in:
DBotThePony 2025-03-08 16:29:52 +07:00
parent 80708868d5
commit 5bd1717636
Signed by: DBot
GPG Key ID: DCC23B5715498507
4 changed files with 144 additions and 1 deletions

View File

@ -4,7 +4,7 @@ kotlin.code.style=official
specifyKotlinAsDependency=false
projectGroup=ru.dbotthepony.kommons
projectVersion=3.1.3
projectVersion=3.2.0
guavaDepVersion=33.0.0
gsonDepVersion=2.8.9

View File

@ -0,0 +1,27 @@
package ru.dbotthepony.kommons.random
import java.util.random.RandomGenerator
/**
* Classical LCG PRNG, utilizing [MULTIPLIER] and [INCREMENT] as constants.
*
* Internal state is presented as 64-bit integer, and high-order bits of internal state are
* used to generate numbers.
*/
open class LCG64Random(private var seed: Long) : RandomGenerator {
final override fun nextLong(): Long {
val a = nextInt().toLong()
val b = nextInt().toLong() and 0xFFFFFFFFL
return a.shl(32) or b
}
final override fun nextInt(): Int {
this.seed = MULTIPLIER * this.seed + INCREMENT
return this.seed.ushr(32).toInt()
}
companion object {
const val MULTIPLIER = 6364136223846793005
const val INCREMENT = 1442695040888963407
}
}

View File

@ -0,0 +1,58 @@
package ru.dbotthepony.kommons.random
import java.util.random.RandomGenerator
open class Xoshiro256PlusPlusRandom protected constructor(
private var s0: Long,
private var s1: Long,
private var s2: Long,
private var s3: Long,
mark: Nothing?
) : RandomGenerator {
init {
if (s0 or s1 or s2 or s3 == 0L) {
s0 = 0x73CF3D83FFF44FF3L
s1 = 0x6412312B70F3CD37L
s2 = -0X6BB4C4E1327BFDCFL
s3 = -0X4BE0F5BB5F3F5240L
}
}
constructor(s0: Long, s1: Long, s2: Long, s3: Long) : this(s0, s1, s2, s3, null) {
// discard some values so generator can get going if provided seed was "weak"
for (i in 0 until 32)
nextLong()
}
constructor(seed: Long) : this(1L, 0L, 0L, 0L, null) {
val rng = LCG64Random(seed)
s0 = rng.nextLong()
s1 = rng.nextLong()
s2 = rng.nextLong()
s3 = rng.nextLong()
}
final override fun nextLong(): Long {
val result = (s0 + s3).rotateLeft(23) + s1
val t = s1.shl(17)
s2 = s2.xor(s0)
s3 = s3.xor(s1)
s1 = s1.xor(s2)
s0 = s0.xor(s3)
s2 = s2.xor(t)
s3 = s3.rotateLeft(45)
return result
}
companion object {
@JvmStatic
fun raw(
s0: Long,
s1: Long,
s2: Long,
s3: Long,
): Xoshiro256PlusPlusRandom {
return Xoshiro256PlusPlusRandom(s0, s1, s2, s3, null)
}
}
}

View File

@ -0,0 +1,58 @@
package ru.dbotthepony.kommons.random
import java.util.random.RandomGenerator
open class Xoshiro256StarStarRandom protected constructor(
private var s0: Long,
private var s1: Long,
private var s2: Long,
private var s3: Long,
mark: Nothing?
) : RandomGenerator {
init {
if (s0 or s1 or s2 or s3 == 0L) {
s0 = 0x73CF3D83FFF44FF3L
s1 = 0x6412312B70F3CD37L
s2 = -0X6BB4C4E1327BFDCFL
s3 = -0X4BE0F5BB5F3F5240L
}
}
constructor(s0: Long, s1: Long, s2: Long, s3: Long) : this(s0, s1, s2, s3, null) {
// discard some values so generator can get going if provided seed was "weak"
for (i in 0 until 32)
nextLong()
}
constructor(seed: Long) : this(1L, 0L, 0L, 0L, null) {
val rng = LCG64Random(seed)
s0 = rng.nextLong()
s1 = rng.nextLong()
s2 = rng.nextLong()
s3 = rng.nextLong()
}
final override fun nextLong(): Long {
val result = (s1 * 5).rotateLeft(7) * 9
val t = s1.shl(17)
s2 = s2.xor(s0)
s3 = s3.xor(s1)
s1 = s1.xor(s2)
s0 = s0.xor(s3)
s2 = s2.xor(t)
s3 = s3.rotateLeft(45)
return result
}
companion object {
@JvmStatic
fun raw(
s0: Long,
s1: Long,
s2: Long,
s3: Long,
): Xoshiro256StarStarRandom {
return Xoshiro256StarStarRandom(s0, s1, s2, s3, null)
}
}
}