Skip to content

Commit f6f5072

Browse files
authored
Fix weighted RandomSelector returning heavily biased results due to incorrect binary search (#159)
2 parents 22ce91d + 381d1cb commit f6f5072

File tree

2 files changed

+15
-7
lines changed

2 files changed

+15
-7
lines changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
77
javaVersion=21
88
mcVersion=1.21.10
99
group=dev.slne.surf
10-
version=1.21.10-2.40.2
10+
version=1.21.10-2.40.3
1111
relocationPrefix=dev.slne.surf.surfapi.libs
1212
snapshot=false

surf-api-core/surf-api-core-api/src/main/kotlin/dev/slne/surf/surfapi/core/api/random/RandomSelectorImpl.kt

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,20 @@ internal class RandomSelectorImpl<E>(
1919

2020
override fun pick(randomGenerator: RandomGenerator): E {
2121
val totalWeight = cumulativeWeights.getDouble(cumulativeWeights.size - 1)
22-
val randomValue = randomGenerator.nextDouble(totalWeight)
23-
24-
val index = cumulativeWeights.binarySearch { if (it < randomValue) -1 else 0 }
25-
.let { if (it < 0) -(it + 1) else it }
26-
27-
return elements[index]
22+
val r = randomGenerator.nextDouble(totalWeight)
23+
24+
// lower_bound search for first cumulative >= r
25+
var lo = 0
26+
var hi = cumulativeWeights.size - 1
27+
while (lo < hi) {
28+
val mid = (lo + hi) ushr 1
29+
if (r <= cumulativeWeights.getDouble(mid)) {
30+
hi = mid
31+
} else {
32+
lo = mid + 1
33+
}
34+
}
35+
return elements[lo]
2836
}
2937

3038
override fun flow(randomGenerator: RandomGenerator): Flow<E> = kotlinx.coroutines.flow.flow {

0 commit comments

Comments
 (0)