How to implement a modular module for each type of room in Kotlin?

I am currently studying Kotlin and trying to create an extension method (infix), which works on all numeric types ( Byte, Long, Floatetc.). It should work as a Python statement %:

 4   %   3  ==   1      // only this is the same as Java %
 4   %  -3  ==  -2
-4   %   3  ==   2
-4   %  -3  ==  -1

... or like Java Math.floorMod, but it should also work with Doubleor Float:

-4.3 %  3.2 ==   2.1000000000000005

or with any possible combination of these types

 3   %  2.2 ==   0.7999999999999998
 3L  %  2.2f ==   0.7999999999999998

The following works as intended, but only for two Doubleor two 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
    """)
}

Replacing Intwith Number, I get the following error messages:

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'

How can I achieve this for each type of number without copying an insert for each combination of types?

+1
3

( ) - , :

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

, , , , . (read Number), , (. Java- ), , .

. JVM. , , .

P.S . , ?

+3

, , , :

import java.math.BigDecimal
import java.math.BigInteger

inline infix fun <reified T: Number> T.fmod(other: T): T {
  return when {
    this is BigDecimal || other is BigDecimal -> BigDecimal(other.toString()).let {
      (((BigDecimal(this.toString()) % it) + it) % it) as T
    }
    this is BigInteger || other is BigInteger -> BigInteger(other.toString()).let {
      (((BigInteger(this.toString()) % it) + it) % it) as T
    }
    this is Double || other is Double -> other.toDouble().let {
      (((this.toDouble() % it) + it) % it) as T
    }
    this is Float || other is Float -> other.toFloat().let {
      (((this.toFloat() % it) + it) % it) as T
    }
    this is Long || other is Long -> other.toLong().let {
      (((this.toLong() % it) + it) % it) as T
    }
    this is Int || other is Int -> other.toInt().let {
      (((this.toInt() % it) + it) % it) as T
    }
    this is Short || other is Short -> other.toShort().let {
      (((this.toShort() % it) + it) % it) as T
    }
    else -> throw AssertionError()
  }
}

assert(BigDecimal("2.1") == BigDecimal("-4.3") fmod BigDecimal("3.2"))
assert(BigInteger("2") == BigInteger("-4") fmod BigInteger("3"))
assert(2 == -4 fmod 3)
assert(2L == -4L fmod 3L)

assert(0.7999999999999998 == 3 fmod 2.2)
assert(0.79999995f == 3L fmod 2.2f)

, reified ( ) , . , - ( - ).

+1

Here's a completely general higher order approach without any reflection or casting:

inline fun <T> T.fmod(other: T, mod: T.(T) -> T, plus: T.(T) -> T) =
     this.mod(other).plus(other).mod(other)

assert(BigDecimal("2.1") == BigDecimal("-4.3").fmod(BigDecimal("3.2"), BigDecimal::mod, BigDecimal::plus))
assert(2L == -4L.fmod(3L, Long::mod, Long::plus))

However, it is not so beautiful.

0
source

Source: https://habr.com/ru/post/1653166/


All Articles