Implement LC random generator and Collection.shuffle
This commit is contained in:
committed by
Pavel Punegov
parent
b6c7d2d7c3
commit
96b0d10746
@@ -493,6 +493,15 @@ task runtime_basic_exit(type: RunStandaloneKonanTest) {
|
||||
expectedExitStatus = 42
|
||||
}
|
||||
|
||||
task runtime_random(type: RunKonanTest) {
|
||||
source = "runtime/basic/random.kt"
|
||||
}
|
||||
|
||||
task runtime_worker_random(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32')
|
||||
source = "runtime/basic/worker_random.kt"
|
||||
}
|
||||
|
||||
task hello0(type: RunKonanTest) {
|
||||
goldValue = "Hello, world!\n"
|
||||
source = "runtime/basic/hello0.kt"
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package runtime.basic.random
|
||||
|
||||
import kotlin.collections.*
|
||||
import kotlin.random.*
|
||||
import kotlin.system.*
|
||||
import kotlin.test.*
|
||||
|
||||
/**
|
||||
* Tests that setting the same seed make random generate the same sequence
|
||||
*/
|
||||
private inline fun <reified T> testReproducibility(seed: Long, generator: () -> T) {
|
||||
// Reset seed. This will make Random to start a new sequence
|
||||
Random.seed = seed
|
||||
val first = Array<T>(50, { i -> generator() }).toList()
|
||||
|
||||
// Reset seed and try again
|
||||
Random.seed = seed
|
||||
val second = Array<T>(50, { i -> generator() }).toList()
|
||||
assertTrue(first == second, "FAIL: got different sequences of generated values " +
|
||||
"first: $first, second: $second")
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that setting seed makes random generate different sequence.
|
||||
*/
|
||||
private inline fun <reified T> testDifference(generator: () -> T) {
|
||||
Random.seed = 12345678L
|
||||
val first = Array<T>(100, { i -> generator() }).toList()
|
||||
|
||||
Random.seed = 87654321L
|
||||
val second = Array<T>(100, { i -> generator() }).toList()
|
||||
assertTrue(first != second, "FAIL: got the same sequence of generated values " +
|
||||
"first: $first, second: $second")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInts() {
|
||||
testReproducibility(getTimeMillis(), { Random.nextInt() })
|
||||
testReproducibility(Long.MAX_VALUE, { Random.nextInt() })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLong() {
|
||||
testReproducibility(getTimeMillis(), { Random.nextLong() })
|
||||
testReproducibility(Long.MAX_VALUE, { Random.nextLong() })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDiffInt() = testDifference { Random.nextInt() }
|
||||
|
||||
@Test
|
||||
fun testDiffLong() = testDifference { Random.nextLong() }
|
||||
|
||||
@Test
|
||||
fun testBoundInt() {
|
||||
testReproducibility(1000L, { Random.nextInt(1000) })
|
||||
|
||||
// test bounds
|
||||
val bound = 5000
|
||||
val a = Array<Int>(100, { Random.nextInt(bound) })
|
||||
a.forEach {
|
||||
assertTrue(it >= 0, "Should be: $it >= 0")
|
||||
assertTrue(it < bound, "Should be: $it < $bound")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package runtime.basic.worker_random
|
||||
|
||||
import konan.worker.*
|
||||
import kotlin.collections.*
|
||||
import kotlin.random.*
|
||||
import kotlin.system.*
|
||||
import kotlin.test.*
|
||||
|
||||
@Test
|
||||
fun testRandomWorkers() {
|
||||
val seed = getTimeMillis()
|
||||
val workers = Array(5, { _ -> startWorker()})
|
||||
|
||||
val attempts = 3
|
||||
val results = Array(attempts, { ArrayList<Int>() } )
|
||||
for (attempt in 0 until attempts) {
|
||||
Random.seed = seed
|
||||
// Produce a list of random numbers in each worker
|
||||
val futures = Array(workers.size, { workerIndex ->
|
||||
workers[workerIndex].schedule(TransferMode.CHECKED, { workerIndex }) { input ->
|
||||
Array(10, { Random.nextInt() }).toList()
|
||||
}
|
||||
})
|
||||
// Now collect all results into current attempt's list
|
||||
val futureSet = futures.toSet()
|
||||
for (i in 0 until futureSet.size) {
|
||||
val ready = futureSet.waitForMultipleFutures(10000)
|
||||
ready.forEach { results[attempt].addAll(it.result()) }
|
||||
}
|
||||
}
|
||||
|
||||
workers.forEach {
|
||||
it.requestTermination().consume { _ -> }
|
||||
}
|
||||
}
|
||||
@@ -94,17 +94,12 @@ class MutableCollectionTest {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Kotlin/JVM only: java.util.Collections.fill(this, value)
|
||||
@Test fun listFill() {
|
||||
val list = MutableList(3) { it }
|
||||
list.fill(42)
|
||||
assertEquals(listOf(42, 42, 42), list)
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// shuffle is Kotlin/JVM only method
|
||||
@Test fun shuffled() {
|
||||
val list = MutableList(100) { it }
|
||||
val shuffled = list.shuffled()
|
||||
@@ -113,5 +108,4 @@ class MutableCollectionTest {
|
||||
assertEquals(list.toSet(), shuffled.toSet())
|
||||
assertEquals(list.size, shuffled.distinct().size)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package kotlin.collections
|
||||
|
||||
import kotlin.comparisons.*
|
||||
import kotlin.random.*
|
||||
|
||||
// Copies typed varargs array to an array of objects
|
||||
internal actual fun <T> Array<out T>.copyToArrayOfAny(isVarargs: Boolean): Array<out Any?> =
|
||||
@@ -229,13 +230,10 @@ public actual fun <T> MutableList<T>.fill(value: T): Unit {
|
||||
*
|
||||
* See: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
|
||||
*/
|
||||
@FixmeRandom
|
||||
@SinceKotlin("1.2")
|
||||
public actual fun <T> MutableList<T>.shuffle(): Unit {
|
||||
for (i in lastIndex downTo 1) {
|
||||
// FIXME: implement a good random
|
||||
//val j = rand(i + 1)
|
||||
val j = i / 2
|
||||
val j = Random.nextInt(i + 1)
|
||||
val copy = this[i]
|
||||
this[i] = this[j]
|
||||
this[j] = copy
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package kotlin.random
|
||||
|
||||
import konan.internal.*
|
||||
import konan.worker.AtomicLong
|
||||
import kotlin.random.Random.Companion.MULTIPLIER
|
||||
import kotlin.system.getTimeNanos
|
||||
|
||||
abstract class Random {
|
||||
abstract fun nextInt(): Int
|
||||
abstract fun nextInt(bound: Int): Int
|
||||
|
||||
abstract fun nextLong(): Long
|
||||
|
||||
/**
|
||||
* A default pseudo-random linear congruential generator.
|
||||
*/
|
||||
companion object : Random() {
|
||||
private const val MULTIPLIER = 0x5deece66dL
|
||||
private val _seed = AtomicLong(mult(getTimeNanos()))
|
||||
|
||||
/**
|
||||
* Random generator seed value.
|
||||
*/
|
||||
var seed: Long
|
||||
get() = _seed.get()
|
||||
set(value) = update(mult(value))
|
||||
|
||||
private fun mult(value: Long) = (value xor MULTIPLIER) and ((1L shl 48) - 1)
|
||||
|
||||
private fun update(seed: Long) {
|
||||
_seed.compareAndSwap(_seed.get(), seed)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pseudo-random Int number.
|
||||
*/
|
||||
override fun nextInt(): Int {
|
||||
update((seed * MULTIPLIER + 0xbL) and ((1L shl 48) - 1));
|
||||
return (seed ushr 16).toInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pseudo-random Int value between 0 and specified value (exclusive)
|
||||
*/
|
||||
override fun nextInt(bound: Int): Int {
|
||||
if (bound <= 0) throw IllegalArgumentException("Incorrect bound: $bound")
|
||||
|
||||
if (bound and (bound - 1) == 0) {
|
||||
return ((bound * nextInt().toLong()) shr 31).toInt();
|
||||
}
|
||||
|
||||
var m: Int
|
||||
do {
|
||||
var r = nextInt()
|
||||
m = r % bound
|
||||
} while (r - m + (bound - 1) < 0)
|
||||
return m
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pseudo-random Long number.
|
||||
*/
|
||||
override fun nextLong(): Long = (nextInt().toLong() shl 32) + nextInt().toLong()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user