如何在 Kotlin 中为每种 Number 类型实现地板取模?

Jos*_*hua 2 modulo kotlin

目前,我正在学习科特林并试图创建在所有工作的延伸(中缀)方法号码类型ByteLongFloat等)。它应该像 Python 的%运算符一样工作:

 4   %   3  ==   1      // only this is the same as Java's %
 4   %  -3  ==  -2
-4   %   3  ==   2
-4   %  -3  ==  -1
Run Code Online (Sandbox Code Playgroud)

...或者像 Java 的Math.floorMod,但它也应该与Doubleor 一起使用Float

-4.3 %  3.2 ==   2.1000000000000005
Run Code Online (Sandbox Code Playgroud)

或这些类型的任何可能组合

 3   %  2.2 ==   0.7999999999999998
 3L  %  2.2f ==   0.7999999999999998
Run Code Online (Sandbox Code Playgroud)

以下按预期工作,但仅适用于两个Double或两个Int

inline infix fun Double.fmod(other: Double): Number {
    return ((this % other) + other) % other
}

inline infix fun Int.fmod(other: Int): Number {
    return ((this % other) + other) % other
}

// test
fun main(args: Array<String>) {
    println("""
            ${-4.3 fmod 3.2} == 2.1000000000000005

            ${4 fmod 3} == 1
            ${+4 fmod -3} == -2
            ${-4 fmod 3} == 2
            ${-4 fmod -3} == -1
    """)
}
Run Code Online (Sandbox Code Playgroud)

替换IntNumber,我收到以下错误消息:

Error:(21, 18) Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: 
@InlineOnly public operator inline fun BigDecimal.mod(other: BigDecimal): BigDecimal defined in kotlin
Error:(21, 27) Public-API inline function cannot access non-public-API 'internal open fun <ERROR FUNCTION>(): [ERROR : <ERROR FUNCTION RETURN TYPE>] defined in root package'
Error:(21, 36) Public-API inline function cannot access non-public-API 'internal open fun <ERROR FUNCTION>(): [ERROR : <ERROR FUNCTION RETURN TYPE>] defined in root package'
Run Code Online (Sandbox Code Playgroud)

如何在不为每种类型组合复制粘贴的情况下为每种数字类型实现这一点?

vod*_*dan 5

唯一合理的选择(也是最快的)是为您要支持的每一对类型定义运算符:

infix fun Double.fmod(other: Double) = ((this % other) + other) % other

infix fun Int.fmod(other: Int) = ((this % other) + other) % other

infix fun Double.fmod(other: Int) = ((this % other) + other) % other

infix fun Int.fmod(other: Double) = ((this % other) + other) % other
Run Code Online (Sandbox Code Playgroud)

这样就由编译器决定使用什么类型,而不是在运行时。这些函数不是通用的,也不使用继承(read Number),这意味着值没有被装箱(参见 Java 原始装箱),这意味着没有分配对象。

我强烈不建议内联这些函数。将小的优化留给 JVM。不分配对象的事实是这里最大的性能优势。

PS 函数的数量随着支持的类型的平方而增长。您确定需要支持所有类型吗?