From 587978453650ffbc52d27bfa7ef82cc3e5f6d94c Mon Sep 17 00:00:00 2001 From: Pavel Punegov Date: Tue, 10 Jul 2018 19:45:15 +0300 Subject: [PATCH] Fix Random.nextInt with bound that returned negative values --- backend.native/tests/build.gradle | 7 ++++++- backend.native/tests/runtime/basic/random.kt | 17 +++++++++++++---- .../tests/runtime/basic/random_bound.kt | 11 +++++++++++ runtime/src/main/kotlin/kotlin/random/Random.kt | 6 ++---- 4 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 backend.native/tests/runtime/basic/random_bound.kt diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index f3281382c87..c190f4391f8 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -499,8 +499,13 @@ task runtime_random(type: RunKonanTest) { source = "runtime/basic/random.kt" } +task runtime_random_bound(type: RunKonanTest) { + disabled = (project.testTarget == 'wasm32') // Uses exceptions. + source = "runtime/basic/random_bound.kt" +} + task runtime_worker_random(type: RunKonanTest) { - disabled = (project.testTarget == 'wasm32') + disabled = (project.testTarget == 'wasm32') // Uses workers. source = "runtime/basic/worker_random.kt" } diff --git a/backend.native/tests/runtime/basic/random.kt b/backend.native/tests/runtime/basic/random.kt index c4383c6c7fd..5b3ce422880 100644 --- a/backend.native/tests/runtime/basic/random.kt +++ b/backend.native/tests/runtime/basic/random.kt @@ -52,11 +52,20 @@ fun testDiffInt() = testDifference { Random.nextInt() } fun testDiffLong() = testDifference { Random.nextLong() } @Test -fun testBoundInt() { - testReproducibility(1000L, { Random.nextInt(1000) }) +fun testNextInt() { + testReproducibility(getTimeMillis(), { Random.nextInt(1000) }) + testReproducibility(1000L, { Random.nextInt(1024) }) +} - // test bounds - val bound = 5000 +@Test +fun testBoundsNextInt() { + boundTest(5000) + boundTest(32) + boundTest(2) + boundTest(Int.MAX_VALUE) +} + +private fun boundTest(bound: Int) { val a = Array(100, { Random.nextInt(bound) }) a.forEach { assertTrue(it >= 0, "Should be: $it >= 0") diff --git a/backend.native/tests/runtime/basic/random_bound.kt b/backend.native/tests/runtime/basic/random_bound.kt new file mode 100644 index 00000000000..080a511f3a0 --- /dev/null +++ b/backend.native/tests/runtime/basic/random_bound.kt @@ -0,0 +1,11 @@ +package runtime.basic.random_bound + +import kotlin.random.* +import kotlin.test.* + +@Test +fun testBoundsNextInt() { + assertFailsWith("Should fail on bound 0", { Random.nextInt(0) }) + assertFailsWith("Should fail on bound -100", { Random.nextInt(-100) }) + assertFailsWith("Should fail on bound ${Int.MIN_VALUE}", { Random.nextInt(Int.MIN_VALUE) }) +} \ No newline at end of file diff --git a/runtime/src/main/kotlin/kotlin/random/Random.kt b/runtime/src/main/kotlin/kotlin/random/Random.kt index 097680e5bda..5e75769c446 100644 --- a/runtime/src/main/kotlin/kotlin/random/Random.kt +++ b/runtime/src/main/kotlin/kotlin/random/Random.kt @@ -15,9 +15,7 @@ */ package kotlin.random -import konan.internal.* import konan.worker.AtomicLong -import kotlin.random.Random.Companion.MULTIPLIER import kotlin.system.getTimeNanos abstract class Random { @@ -61,12 +59,12 @@ abstract class Random { if (bound <= 0) throw IllegalArgumentException("Incorrect bound: $bound") if (bound and (bound - 1) == 0) { - return ((bound * nextInt().toLong()) shr 31).toInt(); + return ((bound * (nextInt() ushr 1).toLong()) ushr 31).toInt(); } var m: Int do { - var r = nextInt() + var r = nextInt() ushr 1 m = r % bound } while (r - m + (bound - 1) < 0) return m