Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
fuookami.ospf.kotlin.utils.math.Floating.kt Maven / Gradle / Ivy
package fuookami.ospf.kotlin.utils.math
import java.math.*
import kotlin.math.*
import kotlinx.serialization.*
import kotlinx.serialization.json.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import fuookami.ospf.kotlin.utils.concept.*
import fuookami.ospf.kotlin.utils.math.ordinary.*
import fuookami.ospf.kotlin.utils.operator.*
private fun , I : Integer, R : Rational> floatingToRational(
f: F,
converter1: (String) -> I,
converter2: (Long) -> I,
ctor: (I, I) -> R
): R {
val ds = f.toString().trimEnd('0').trimEnd('.')
val index = ds.indexOf('.')
if (index == -1) {
val num = converter1(ds)
return ctor(num, num.constants.one)
}
var num = ds.replace(".", "").toLong()
var den = 1L
for (n in 1 until (ds.length - index)) {
den *= 10L
}
while ((num % 2L == 0L) && (den % 2L == 0L)) {
num /= 2L
den /= 2L
}
while ((num % 5L == 2L) && (den % 5L == 0L)) {
num /= 5L
den /= 5L
}
return ctor(converter2(num), converter2(den))
}
@Suppress("UNCHECKED_CAST")
interface FloatingImpl> : FloatingNumber {
override infix fun eq(rhs: Self) = (this - rhs).abs() <= this.constants.decimalPrecision
override infix fun neq(rhs: Self) = !this.eq(rhs)
override infix fun ls(rhs: Self) = (this - rhs) < -this.constants.decimalPrecision
override infix fun leq(rhs: Self) = (this - rhs) <= this.constants.decimalPrecision
override infix fun gr(rhs: Self) = (this - rhs) > this.constants.decimalPrecision
override infix fun geq(rhs: Self) = (this - rhs) >= -this.constants.decimalPrecision
override fun inc(): Self = this + constants.one
override fun dec(): Self = this - constants.one
override fun sqr() = pow(2)
override fun cub() = pow(3)
override fun sqrt(): Self = pow(constants.one / constants.two) as Self
override fun cbrt(): Self = pow(constants.one / constants.three) as Self
override fun lg(): Self? = log(constants.ten) as Self?
override fun ln(): Self? = log(constants.e) as Self?
override fun toRtn8() = floatingToRational(value(), { Int8(it.toByte()) }, { Int8(it.toByte()) }, Rtn8::invoke)
override fun toRtn16() =
floatingToRational(value(), { Int16(it.toShort()) }, { Int16(it.toShort()) }, Rtn16::invoke)
override fun toRtn32() = floatingToRational(value(), { Int32(it.toInt()) }, { Int32(it.toInt()) }, Rtn32::invoke)
override fun toRtn64() = floatingToRational(value(), { Int64(it.toLong()) }, { Int64(it) }, Rtn64::invoke)
override fun toRtnX() = floatingToRational(value(), { IntX(it) }, { IntX(it) }, RtnX::invoke)
override fun toURtn8() =
floatingToRational(value(), { UInt8(it.toUByte()) }, { UInt8(it.toUByte()) }, URtn8::invoke)
override fun toURtn16() =
floatingToRational(value(), { UInt16(it.toUShort()) }, { UInt16(it.toUShort()) }, URtn16::invoke)
override fun toURtn32() =
floatingToRational(value(), { UInt32(it.toUInt()) }, { UInt32(it.toUInt()) }, URtn32::invoke)
override fun toURtn64() =
floatingToRational(value(), { UInt64(it.toULong()) }, { UInt64(it.toULong()) }, URtn64::invoke)
override fun toURtnX() = floatingToRational(value(), { UIntX(it) }, { UIntX(it) }, URtnX::invoke)
}
data object Flt32Serializer : KSerializer {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Flt32", PrimitiveKind.DOUBLE)
override fun serialize(encoder: Encoder, value: Flt32) {
encoder.encodeDouble(value.value.toDouble())
}
override fun deserialize(decoder: Decoder): Flt32 {
return Flt32(decoder.decodeDouble().toFloat())
}
}
@JvmInline
@Serializable(with = Flt32Serializer::class)
value class Flt32(internal val value: Float) : FloatingImpl, Copyable {
companion object : FloatingNumberConstants {
override val zero: Flt32 get() = Flt32(0.0F)
override val one: Flt32 get() = Flt32(1.0F)
override val two: Flt32 get() = Flt32(2.0F)
override val three: Flt32 get() = Flt32(3.0F)
override val five: Flt32 get() = Flt32(5.0F)
override val ten: Flt32 get() = Flt32(10.0F)
override val minimum: Flt32 get() = Flt32(-Float.MAX_VALUE)
override val maximum: Flt32 get() = Flt32(Float.MAX_VALUE)
override val decimalDigits: Int get() = 6
override val decimalPrecision: Flt32 get() = Flt32(1.19209e-07F)
override val epsilon: Flt32 get() = Flt32(Float.MIN_VALUE)
override val nan: Flt32 get() = Flt32(Float.NaN)
override val infinity: Flt32 get() = Flt32(Float.POSITIVE_INFINITY)
override val negativeInfinity: Flt32 get() = Flt32(Float.NEGATIVE_INFINITY)
override val pi: Flt32 get() = Flt32(PI.toFloat())
override val e: Flt32 get() = Flt32(E.toFloat())
}
override val constants: FloatingNumberConstants get() = Companion
override fun copy() = Flt32(value)
override fun toString() = value.toString()
override fun partialOrd(rhs: Flt32) = orderOf(value.compareTo(rhs.value))
override fun partialEq(rhs: Flt32) = (value.compareTo(rhs.value) == 0)
override fun unaryMinus() = Flt32(-value)
override fun abs() = Flt32(abs(value))
override fun reciprocal() = Flt32(1.0F / value)
override fun plus(rhs: Flt32) = Flt32(value + rhs.value)
override fun minus(rhs: Flt32) = Flt32(value - rhs.value)
override fun times(rhs: Flt32) = Flt32(value * rhs.value)
override fun div(rhs: Flt32) = Flt32(value / rhs.value)
override fun intDiv(rhs: Flt32) = Flt32(value - value % rhs.value)
override fun rem(rhs: Flt32) = Flt32(value % rhs.value)
@Throws(IllegalArgumentException::class)
override fun log(base: FloatingNumber<*>): FloatingNumber<*>? = when (base) {
is Flt32 -> Flt32(log(value, base.value))
is Flt64 -> Flt64(log(value.toDouble(), base.value))
is FltX -> toFltX().log(base)
else -> throw IllegalArgumentException("Unknown argument type to Flt32.log: ${base.javaClass}")
}
override fun pow(index: Int) = pow(copy(), index, Flt32)
@Throws(IllegalArgumentException::class)
override fun pow(index: FloatingNumber<*>): FloatingNumber<*> = when (index) {
is Flt32 -> Flt32(value.pow(index.value))
is Flt64 -> Flt64(value.toDouble().pow(index.value))
is FltX -> toFltX().pow(index)
else -> throw IllegalArgumentException("Unknown argument type to Flt32.pow: ${index.javaClass}")
}
override fun exp() = Flt32(exp(value))
override fun toInt8() = Int8(value.toInt().toByte())
override fun toInt16() = Int16(value.toInt().toShort())
override fun toInt32() = Int32(value.toInt())
override fun toInt64() = Int64(value.toLong())
override fun toIntX() = IntX(value.toString())
override fun toUInt8() = UInt8(value.toUInt().toUByte())
override fun toUInt16() = UInt16(value.toUInt().toUShort())
override fun toUInt32() = UInt32(value.toUInt())
override fun toUInt64() = UInt64(value.toULong())
override fun toUIntX() = UIntX(value.toString())
override fun toFlt32() = copy()
override fun toFlt64() = Flt64(value.toDouble())
override fun toFltX() = FltX(value.toDouble())
fun toFloat() = value
fun floor() = Flt32(floor(value))
fun ceil() = Flt32(ceil(value))
fun round() = Flt32(round(value))
fun floorTo(precision: Int = decimalDigits) = Flt32(floor(value * 10.0F.pow(precision)) / 10.0F.pow(precision))
fun ceilTo(precision: Int = decimalDigits) = Flt32(ceil(value * 10.0F.pow(precision)) / 10.0F.pow(precision))
fun roundTo(precision: Int = decimalDigits) = Flt32(round(value * 10.0F.pow(precision)) / 10.0F.pow(precision))
}
data object Flt64Serializer : KSerializer {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Flt64", PrimitiveKind.DOUBLE)
override fun serialize(encoder: Encoder, value: Flt64) {
encoder.encodeDouble(value.value)
}
override fun deserialize(decoder: Decoder): Flt64 {
return Flt64(decoder.decodeDouble())
}
}
@JvmInline
@Serializable(with = Flt64Serializer::class)
value class Flt64(internal val value: Double) : FloatingImpl, Copyable {
constructor(value: Int) : this(value.toDouble())
companion object : FloatingNumberConstants {
override val zero: Flt64 get() = Flt64(0.0)
override val one: Flt64 get() = Flt64(1.0)
override val two: Flt64 get() = Flt64(2.0)
override val three: Flt64 get() = Flt64(3.0)
override val five: Flt64 get() = Flt64(5.0)
override val ten: Flt64 get() = Flt64(10.0)
override val minimum: Flt64 get() = Flt64(-Double.MAX_VALUE)
override val maximum: Flt64 get() = Flt64(Double.MAX_VALUE)
override val decimalDigits: Int get() = 15
override val decimalPrecision: Flt64 get() = Flt64(2.22045e-16)
override val nan: Flt64 get() = Flt64(Double.NaN)
override val epsilon: Flt64 get() = Flt64(Double.MIN_VALUE)
override val infinity: Flt64 get() = Flt64(Double.POSITIVE_INFINITY)
override val negativeInfinity: Flt64 get() = Flt64(Double.NEGATIVE_INFINITY)
override val pi: Flt64 get() = Flt64(PI)
override val e: Flt64 get() = Flt64(E)
}
override val constants: FloatingNumberConstants get() = Flt64
override fun copy() = Flt64(value)
override fun toString() = value.toString()
override fun partialOrd(rhs: Flt64) = orderOf(value.compareTo(rhs.value))
override fun partialEq(rhs: Flt64) = (value.compareTo(rhs.value) == 0)
override fun unaryMinus() = Flt64(-value)
override fun abs() = Flt64(abs(value))
override fun reciprocal() = Flt64(1.0 / value)
override fun plus(rhs: Flt64) = Flt64(value + rhs.value)
override fun minus(rhs: Flt64) = Flt64(value - rhs.value)
override fun times(rhs: Flt64) = Flt64(value * rhs.value)
override fun div(rhs: Flt64) = Flt64(value / rhs.value)
override fun intDiv(rhs: Flt64) = Flt64(value - value % rhs.value)
override fun rem(rhs: Flt64) = Flt64(value % rhs.value)
@Throws(IllegalArgumentException::class)
override fun log(base: FloatingNumber<*>): FloatingNumber<*>? = when (base) {
is Flt32 -> Flt64(log(value, base.value.toDouble()))
is Flt64 -> Flt64(log(value, base.value))
is FltX -> toFltX().log(base)
else -> throw IllegalArgumentException("Unknown argument type to Flt64.log: ${base.javaClass}")
}
override fun pow(index: Int) = pow(copy(), index, Flt64)
@Throws(IllegalArgumentException::class)
override fun pow(index: FloatingNumber<*>): FloatingNumber<*> = when (index) {
is Flt32 -> Flt64(value.pow(index.value.toDouble()))
is Flt64 -> Flt64(value.pow(index.value))
is FltX -> toFltX().pow(index)
else -> throw IllegalArgumentException("Unknown argument type to Flt64.pow: ${index.javaClass}")
}
override fun exp() = Flt64(exp(value))
override fun toInt8() = Int8(value.toInt().toByte())
override fun toInt16() = Int16(value.toInt().toShort())
override fun toInt32() = Int32(value.toInt())
override fun toInt64() = Int64(value.toLong())
override fun toIntX() = IntX(value.toString())
override fun toUInt8() = UInt8(value.toUInt().toUByte())
override fun toUInt16() = UInt16(value.toUInt().toUShort())
override fun toUInt32() = UInt32(value.toUInt())
override fun toUInt64() = UInt64(value.toULong())
override fun toUIntX() = UIntX(value.toString())
override fun toFlt32() = Flt32(value.toFloat())
override fun toFlt64() = copy()
override fun toFltX() = FltX(value)
fun toDouble() = value
fun floor() = Flt64(floor(value))
fun ceil() = Flt64(ceil(value))
fun round() = Flt64(round(value))
fun floorTo(precision: Int = decimalDigits) = Flt64(floor(value * 10.0.pow(precision)) / 10.0.pow(precision))
fun ceilTo(precision: Int = decimalDigits) = Flt64(ceil(value * 10.0.pow(precision)) / 10.0.pow(precision))
fun roundTo(precision: Int = decimalDigits) = Flt64(round(value * 10.0.pow(precision)) / 10.0.pow(precision))
}
data object FltXSerializer : KSerializer {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("FltX", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: FltX) {
encoder.encodeString(value.value.toString())
}
override fun deserialize(decoder: Decoder): FltX {
return FltX(decoder.decodeString())
}
}
data object FltXJsonSerializer : KSerializer {
@OptIn(ExperimentalSerializationApi::class, InternalSerializationApi::class)
override val descriptor: SerialDescriptor = SerialDescriptor("FltX", JsonElement::class.serializer().descriptor)
@OptIn(InternalSerializationApi::class)
override fun deserialize(decoder: Decoder): FltX {
decoder as? JsonDecoder ?: throw IllegalStateException(
"This serializer can be used only with Json format." + "Expected Decoder to be JsonDecoder, got ${this::class}"
)
val element = decoder.decodeSerializableValue(JsonPrimitive::class.serializer())
return FltX(element.content, FltX.decimalDigits)
}
override fun serialize(encoder: Encoder, value: FltX) {
encoder.encodeString(value.toPlainString())
}
}
@JvmInline
@Serializable(with = FltXSerializer::class)
value class FltX(internal val value: BigDecimal) : FloatingImpl, Copyable {
companion object : FloatingNumberConstants {
override val zero: FltX get() = FltX(BigDecimal.ZERO)
override val one: FltX get() = FltX(BigDecimal.ONE)
override val two: FltX get() = FltX(2L)
override val three: FltX get() = FltX(3L)
override val five: FltX get() = FltX(5L)
override val ten: FltX get() = FltX(10L)
override val minimum: FltX get() = FltX(-Double.MAX_VALUE)
override val maximum: FltX get() = FltX(Double.MAX_VALUE)
override val decimalDigits: Int get() = 18
override val decimalPrecision: FltX get() = FltX(1e-18)
override val epsilon: FltX get() = decimalPrecision
override val pi: FltX get() = FltX(PI.toBigDecimal())
override val e: FltX get() = FltX(E.toBigDecimal())
}
constructor(value: Double, scale: Int = decimalDigits, roundingMode: RoundingMode = RoundingMode.HALF_UP) : this(BigDecimal.valueOf(value).setScale(scale, roundingMode))
constructor(value: Long, scale: Int = 2, roundingMode: RoundingMode = RoundingMode.HALF_UP) : this(BigDecimal.valueOf(value).setScale(scale, roundingMode))
constructor(value: String, scale: Int = decimalDigits, roundingMode: RoundingMode = RoundingMode.HALF_UP) : this(BigDecimal(value).setScale(scale, roundingMode))
fun withScale(scale: Int) = FltX(value.setScale(scale))
fun withScale(scale: Int, roundingMode: RoundingMode) = FltX(value.setScale(scale, roundingMode))
override val constants: FloatingNumberConstants get() = Companion
override fun copy() = FltX(value)
override fun toString() = value.toString()
fun toEngineeringString(): String = value.stripTrailingZeros().toEngineeringString()
fun toPlainString(): String = value.stripTrailingZeros().toPlainString()
override fun partialOrd(rhs: FltX) = orderOf(value.compareTo(rhs.value))
override fun partialEq(rhs: FltX) = (value.compareTo(rhs.value) == 0)
override fun unaryMinus() = FltX(-value)
override fun abs() = FltX(value.abs())
override fun reciprocal() = FltX(one.value / value)
override fun plus(rhs: FltX) = FltX(value + rhs.value)
override fun minus(rhs: FltX) = FltX(value - rhs.value)
override fun times(rhs: FltX) = FltX(value * rhs.value)
override fun div(rhs: FltX) = FltX(value / rhs.value)
override fun intDiv(rhs: FltX) = FltX(value - value % rhs.value)
override fun rem(rhs: FltX) = FltX(value % rhs.value)
@Throws(IllegalArgumentException::class)
override fun log(base: FloatingNumber<*>): FltX? = when (base) {
is Flt32 -> log(this, base.toFltX(), FltX)
is Flt64 -> log(this, base.toFltX(), FltX)
is FltX -> log(this, base, FltX)
else -> throw IllegalArgumentException("Unknown argument type to FltX.log: ${base.javaClass}")
}
override fun pow(index: Int) = FltX(value.pow(index))
@Throws(IllegalArgumentException::class)
override fun pow(index: FloatingNumber<*>): FltX = when (index) {
is Flt32 -> pow(this, index.toFltX(), FltX)
is Flt64 -> pow(this, index.toFltX(), FltX)
is FltX -> pow(this, index, FltX)
else -> throw IllegalArgumentException("Unknown argument type to FltX.pow: ${index.javaClass}")
}
override fun exp() = FltX(exp(value.toDouble()))
override fun toInt8() = Int8(value.toInt().toByte())
override fun toInt16() = Int16(value.toInt().toShort())
override fun toInt32() = Int32(value.toInt())
override fun toInt64() = Int64(value.toLong())
override fun toIntX() = IntX(value.toString())
override fun toUInt8() = UInt8(value.toInt().toUByte())
override fun toUInt16() = UInt16(value.toInt().toUShort())
override fun toUInt32() = UInt32(value.toLong().toUInt())
override fun toUInt64() = UInt64(value.toLong().toULong())
override fun toUIntX() = UIntX(value.toString())
override fun toFlt32() = Flt32(value.toFloat())
override fun toFlt64() = Flt64(value.toDouble())
override fun toFltX() = copy()
fun toDecimal() = value
fun floor(): FltX {
val scale = value.scale()
return FltX(value.setScale(0, RoundingMode.FLOOR).setScale(scale))
}
fun ceil(): FltX {
val scale = value.scale()
return FltX(value.setScale(0, RoundingMode.CEILING).setScale(scale))
}
fun round(): FltX {
val scale = value.scale()
return FltX(value.setScale(0, RoundingMode.HALF_UP).setScale(scale))
}
fun floorTo(precision: Int = decimalDigits): FltX {
val scale = value.scale()
return FltX(value.setScale(precision, RoundingMode.FLOOR).setScale(scale))
}
fun ceilTo(precision: Int = decimalDigits): FltX {
val scale = value.scale()
return FltX(value.setScale(precision, RoundingMode.CEILING).setScale(scale))
}
fun roundTo(precision: Int = decimalDigits): FltX {
val scale = value.scale()
return FltX(value.setScale(precision, RoundingMode.HALF_UP).setScale(scale))
}
}
fun String.toFlt32() = Flt32(toFloat())
fun String.toFlt32OrNull() = toFloatOrNull()?.let { Flt32(it) }
fun String.toFlt64() = Flt64(toDouble())
fun String.toFlt64OrNull() = toDoubleOrNull()?.let { Flt64(it) }
fun String.toFltX() = FltX(toBigDecimal())
fun String.toFltXOrNull() = toBigDecimalOrNull()?.let { FltX(it) }