I've been trying to implement a weighted average function using exponentially decreasing weights as described in this Wikipedia article.
I think I'm failing! I'm a bit too thick to fill in a few of the gaps that seem to be missing from the Wikipedia article, since it seems to be missing a nice clean one-line definition of what the function should produce given m samples, ie what does f(x1, x2, ... xm) = ?.
Here's my attempt to implement it in Kotlin, where numbers contains my m samples, and fraction is the Δ referred to in the Wikipedia article:
fun weightedAverage(numbers: List<Long>, fraction: BigDecimal): Long? {
if (! (zero < fraction && fraction < one)) {
throw IllegalArgumentException("fraction must be in (0..1), but $fraction is outside that range")
}
return when(numbers.size) {
0 -> null
1 -> numbers.first()
else -> multiPointWeightedAverage(numbers, fraction)
}
}
private fun multiPointWeightedAverage(numbers: List<Long>, fraction: BigDecimal): Long {
val m = numbers.size
var w = one - fraction
val w_m = w.pow(m)
val V1 = (one - w_m) / fraction
var sum = w * BigDecimal(numbers[0])
for (i in 1..m-1) {
w /= V1
sum += w * BigDecimal(numbers[1])
}
return sum.setScale(0, RoundingMode.HALF_UP).toLong()
}
But I'm pretty sure this is wrong, because, eg, I expect weightedAverage(listOf(1L, 1L, 1L), BigDecimal(0.9))
to produce the output 1, but it ends up spitting out 0.27125... which rounds down to zero.
Can you help me correct my implementation, hopefully explaining what wrong assumption or step I made?