@@ -19,8 +19,19 @@ import kotlin.reflect.typeOf
1919private val logger = KotlinLogging .logger { }
2020
2121/* *
22- * p-quantile: the k'th q-quantile, where p = k/q.
22+ * Returns the p-quantile: the k'th q-quantile, where p = k/q.
2323 *
24+ * When [method] is a [QuantileEstimationMethod.Selecting] method,
25+ * [this] can be a sequence with any self-comparable type.
26+ * The returned value will be selected from the sequence.
27+ *
28+ * Otherwise, when [method] is a [QuantileEstimationMethod.Interpolating] method,
29+ * [this] can only be a sequence with primitive number types.
30+ * The returned value will be [Double].
31+ *
32+ * Nulls are not allowed. If NaN is among the values, it will be returned.
33+ *
34+ * @see QuantileEstimationMethod
2435 */
2536internal fun <T : Comparable <T >> Sequence<Any>.quantileOrNull (
2637 p : Double ,
@@ -55,7 +66,12 @@ internal fun <T : Comparable<T>> Sequence<Any>.quantileOrNull(
5566 }
5667
5768 // propagate NaN to return if they are not to be skipped
58- if (type.canBeNaN && ! skipNaN && any { it.isNaN }) return Double .NaN
69+ if (type.canBeNaN && ! skipNaN && any { it.isNaN }) {
70+ // ensure that using a selecting quantile estimation method always returns the same type as the input
71+ if (type == typeOf<Float >() && method is QuantileEstimationMethod .Selecting ) return Float .NaN
72+
73+ return Double .NaN
74+ }
5975
6076 val list = when {
6177 type.canBeNaN -> filter { ! it.isNaN }
@@ -201,7 +217,6 @@ internal sealed interface QuantileEstimationMethod<Value : Comparable<Value>, In
201217 return values.quickSelect(h)
202218 }
203219 }
204-
205220 }
206221
207222 // TODO add R2, R4, R5, R6, R9
@@ -227,7 +242,7 @@ internal sealed interface QuantileEstimationMethod<Value : Comparable<Value>, In
227242 return values.quickSelect(floor(h).toInt() - 1 ) + (h - floor(h)) * (
228243 values.quickSelect(ceil(h).toInt() - 1 ) -
229244 values.quickSelect(floor(h).toInt() - 1 )
230- )
245+ )
231246 }
232247 }
233248 }
0 commit comments