From 5ebc7008ebd6916e83848896006a0c8354423627 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 24 Feb 2024 23:14:22 +0700 Subject: [PATCH] Remove Decimal since it is quite specific, and has compile-time constraints --- gradle.properties | 2 +- .../dbotthepony/kommons/io/DelegateSyncher.kt | 6 - .../kommons/io/InputStreamUtils.kt | 9 - .../kommons/io/OutputStreamUtils.kt | 7 - .../ru/dbotthepony/kommons/io/StreamCodec.kt | 3 - .../ru/dbotthepony/kommons/math/Decimal.kt | 1557 ----------------- 6 files changed, 1 insertion(+), 1583 deletions(-) delete mode 100644 src/main/kotlin/ru/dbotthepony/kommons/math/Decimal.kt diff --git a/gradle.properties b/gradle.properties index caf963d..1bbd1bb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ kotlin.code.style=official specifyKotlinAsDependency=false projectGroup=ru.dbotthepony.kommons -projectVersion=2.8.2 +projectVersion=2.9.0 guavaDepVersion=33.0.0 gsonDepVersion=2.8.9 diff --git a/src/main/kotlin/ru/dbotthepony/kommons/io/DelegateSyncher.kt b/src/main/kotlin/ru/dbotthepony/kommons/io/DelegateSyncher.kt index 37dbaf4..a19d25c 100644 --- a/src/main/kotlin/ru/dbotthepony/kommons/io/DelegateSyncher.kt +++ b/src/main/kotlin/ru/dbotthepony/kommons/io/DelegateSyncher.kt @@ -7,7 +7,6 @@ import it.unimi.dsi.fastutil.objects.ObjectAVLTreeSet import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet import ru.dbotthepony.kommons.collect.ListenableMap import ru.dbotthepony.kommons.collect.ListenableSet -import ru.dbotthepony.kommons.math.Decimal import ru.dbotthepony.kommons.util.Delegate import ru.dbotthepony.kommons.util.DelegateGetter import ru.dbotthepony.kommons.util.DelegateSetter @@ -502,11 +501,6 @@ class DelegateSyncher : Observer { return add(ListenableDelegate.maskSmart(value, getter, setter), UUIDValueCodec) } - @JvmOverloads - fun decimal(value: Decimal = Decimal.ZERO, setter: DelegateSetter = DelegateSetter.passthrough(), getter: DelegateGetter = DelegateGetter.passthrough()): Slot { - return add(ListenableDelegate.maskSmart(value, getter, setter), DecimalValueCodec) - } - @JvmOverloads fun set(codec: StreamCodec, backing: MutableSet = ObjectOpenHashSet()): SetSlot { return add(ListenableSet(backing), codec) diff --git a/src/main/kotlin/ru/dbotthepony/kommons/io/InputStreamUtils.kt b/src/main/kotlin/ru/dbotthepony/kommons/io/InputStreamUtils.kt index c4cf63d..0436053 100644 --- a/src/main/kotlin/ru/dbotthepony/kommons/io/InputStreamUtils.kt +++ b/src/main/kotlin/ru/dbotthepony/kommons/io/InputStreamUtils.kt @@ -2,7 +2,6 @@ package ru.dbotthepony.kommons.io import it.unimi.dsi.fastutil.bytes.ByteArrayList import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap -import ru.dbotthepony.kommons.math.Decimal import ru.dbotthepony.kommons.util.KOptional import java.io.DataInput import java.io.EOFException @@ -290,14 +289,6 @@ fun InputStream.readUUID(): UUID { return UUID(readLong(), readLong()) } -fun InputStream.readDecimal(): Decimal { - val size = readVarInt() - require(size >= 0) { "Negative payload size: $size" } - val bytes = ByteArray(size) - read(bytes) - return Decimal.fromByteArray(bytes) -} - fun , K, V> S.readMap(keyReader: S.() -> K, valueReader: S.() -> V, constructor: (Int) -> M): M { val size = readVarInt() require(size >= 0) { "Negative payload size: $size" } diff --git a/src/main/kotlin/ru/dbotthepony/kommons/io/OutputStreamUtils.kt b/src/main/kotlin/ru/dbotthepony/kommons/io/OutputStreamUtils.kt index 06bb611..5b4e5b5 100644 --- a/src/main/kotlin/ru/dbotthepony/kommons/io/OutputStreamUtils.kt +++ b/src/main/kotlin/ru/dbotthepony/kommons/io/OutputStreamUtils.kt @@ -1,6 +1,5 @@ package ru.dbotthepony.kommons.io -import ru.dbotthepony.kommons.math.Decimal import ru.dbotthepony.kommons.util.IStruct2b import ru.dbotthepony.kommons.util.IStruct2d import ru.dbotthepony.kommons.util.IStruct2f @@ -287,12 +286,6 @@ fun OutputStream.writeStruct4b(value: IStruct4b) { writeShort(value.component4().toInt() and 0xFF) } -fun OutputStream.writeDecimal(value: Decimal) { - val bytes = value.toByteArray() - writeVarInt(bytes.size) - write(bytes) -} - fun S.writeMap(map: Map, keyWriter: S.(K) -> Unit, valueWriter: S.(V) -> Unit) { writeVarInt(map.size) diff --git a/src/main/kotlin/ru/dbotthepony/kommons/io/StreamCodec.kt b/src/main/kotlin/ru/dbotthepony/kommons/io/StreamCodec.kt index 210a1e7..2eafee5 100644 --- a/src/main/kotlin/ru/dbotthepony/kommons/io/StreamCodec.kt +++ b/src/main/kotlin/ru/dbotthepony/kommons/io/StreamCodec.kt @@ -194,7 +194,6 @@ val UUIDValueCodec = StreamCodec.Impl({ s -> UUID(s.readLong(), s.readLong()) }, val VarIntValueCodec = StreamCodec.Impl(DataInputStream::readSignedVarInt, DataOutputStream::writeSignedVarInt) val VarLongValueCodec = StreamCodec.Impl(DataInputStream::readSignedVarLong, DataOutputStream::writeSignedVarLong) val BinaryStringCodec = StreamCodec.Impl(DataInputStream::readBinaryString, DataOutputStream::writeBinaryString) -val DecimalValueCodec = StreamCodec.Impl(DataInputStream::readDecimal, DataOutputStream::writeDecimal) val OptionalBooleanValueCodec = StreamCodec.Optional(BooleanValueCodec) val OptionalByteValueCodec = StreamCodec.Optional(ByteValueCodec) @@ -209,7 +208,6 @@ val OptionalUUIDValueCodec = StreamCodec.Optional(UUIDValueCodec) val OptionalVarIntValueCodec = StreamCodec.Optional(VarIntValueCodec) val OptionalVarLongValueCodec = StreamCodec.Optional(VarLongValueCodec) val OptionalBinaryStringCodec = StreamCodec.Optional(BinaryStringCodec) -val OptionalDecimalValueCodec = StreamCodec.Optional(DecimalValueCodec) val KOptionalBooleanValueCodec = StreamCodec.KOptional(BooleanValueCodec) val KOptionalByteValueCodec = StreamCodec.KOptional(ByteValueCodec) @@ -224,7 +222,6 @@ val KOptionalUUIDValueCodec = StreamCodec.KOptional(UUIDValueCodec) val KOptionalVarIntValueCodec = StreamCodec.KOptional(VarIntValueCodec) val KOptionalVarLongValueCodec = StreamCodec.KOptional(VarLongValueCodec) val KOptionalBinaryStringCodec = StreamCodec.KOptional(BinaryStringCodec) -val KOptionalDecimalValueCodec = StreamCodec.KOptional(DecimalValueCodec) fun > Class.codec() = StreamCodec.Enum(this) fun > KClass.codec() = StreamCodec.Enum(this.java) diff --git a/src/main/kotlin/ru/dbotthepony/kommons/math/Decimal.kt b/src/main/kotlin/ru/dbotthepony/kommons/math/Decimal.kt deleted file mode 100644 index 9584db2..0000000 --- a/src/main/kotlin/ru/dbotthepony/kommons/math/Decimal.kt +++ /dev/null @@ -1,1557 +0,0 @@ -package ru.dbotthepony.kommons.math - -import java.math.BigDecimal -import java.math.BigInteger -import java.math.MathContext -import java.math.RoundingMode - -private val BI_MINUS_ONE = -BigInteger.ONE -private val PERCENTAGE_CONTEXT = MathContext(6) // 6 ибо это число знаков для вычисления процента - -fun Decimal(value: Byte) = Decimal.valueOf(value) -fun Decimal(value: Short) = Decimal.valueOf(value) -fun Decimal(value: Int) = Decimal.valueOf(value) -fun Decimal(value: Long) = Decimal.valueOf(value) -fun Decimal(value: Float) = Decimal.valueOf(value) -fun Decimal(value: Double) = Decimal.valueOf(value) -fun Decimal(value: BigDecimal) = Decimal.valueOf(value) -fun Decimal(value: BigInteger) = Decimal.valueOf(value) -fun Decimal(value: String) = Decimal.valueOf(value) - -inline val BigInteger.isZero get() = this.signum() == 0 -inline val BigInteger.isPositive get() = this.signum() > 0 -inline val BigInteger.isNegative get() = this.signum() < 0 - -inline val BigDecimal.isZero get() = this.signum() == 0 -inline val BigDecimal.isPositive get() = this.signum() > 0 -inline val BigDecimal.isNegative get() = this.signum() < 0 - -val BI_INT_MAX: BigInteger = BigInteger.valueOf(Int.MAX_VALUE.toLong()) -val BI_INT_MIN: BigInteger = BigInteger.valueOf(Int.MIN_VALUE.toLong()) -val BI_LONG_MAX: BigInteger = BigInteger.valueOf(Long.MAX_VALUE) -val BI_LONG_MIN: BigInteger = BigInteger.valueOf(Long.MIN_VALUE) - -val BI_FLOAT_MAX: BigInteger = BigDecimal(Float.MAX_VALUE.toString()).toBigInteger() -val BI_FLOAT_MIN: BigInteger = BigDecimal(Float.MIN_VALUE.toString()).toBigInteger() -val BI_DOUBLE_MAX: BigInteger = BigDecimal(Double.MAX_VALUE.toString()).toBigInteger() -val BI_DOUBLE_MIN: BigInteger = BigDecimal(Double.MIN_VALUE.toString()).toBigInteger() - -/** - * Fixed point arbitrary precision Decimal value. Values of this class embed [BigInteger] unscaled value, scale - * is defined at compile time by [PRECISION]. - */ -sealed class Decimal : Number(), Comparable { - /** - * Whole part of this Decimal - */ - abstract val whole: BigInteger - - /** - * Arbitrary fractional part of this Decimal, as [BigInteger] - * - * Makes sense only when utilized along [PRECISION], [PRECISION_POW], [PRECISION_POW_BI] - */ - abstract val fractional: BigInteger - - /** - * *Signed* normalized (-1,1) fractional part of this Decimal, as [Float] - */ - inline val fractionalFloat: Float get() { - return fractional.toFloat() / PRECISION_FLOAT - } - - /** - * *Signed* normalized (-1,1) fractional part of this Decimal, as [Double] - */ - inline val fractionalDouble: Double get() { - return fractional.toDouble() / PRECISION_DOUBLE - } - - abstract operator fun plus(other: Decimal): Decimal - abstract operator fun minus(other: Decimal): Decimal - abstract operator fun times(other: Decimal): Decimal - abstract operator fun div(other: Decimal): Decimal - - abstract operator fun rem(other: Decimal): Decimal - - // Primitive operators - abstract operator fun plus(other: Float): Decimal - abstract operator fun minus(other: Float): Decimal - abstract operator fun times(other: Float): Decimal - abstract operator fun div(other: Float): Decimal - - abstract operator fun plus(other: Double): Decimal - abstract operator fun minus(other: Double): Decimal - abstract operator fun times(other: Double): Decimal - abstract operator fun div(other: Double): Decimal - - abstract operator fun plus(other: Int): Decimal - abstract operator fun minus(other: Int): Decimal - abstract operator fun times(other: Int): Decimal - abstract operator fun div(other: Int): Decimal - - abstract operator fun plus(other: Long): Decimal - abstract operator fun minus(other: Long): Decimal - abstract operator fun times(other: Long): Decimal - abstract operator fun div(other: Long): Decimal - - abstract operator fun plus(other: BigInteger): Decimal - abstract operator fun minus(other: BigInteger): Decimal - abstract operator fun times(other: BigInteger): Decimal - abstract operator fun div(other: BigInteger): Decimal - // /Primitive operators - - // "de-virtualize" generic method - abstract override fun compareTo(other: Decimal): Int - - override fun toChar(): Char { - return toInt().toChar() - } - - abstract operator fun unaryMinus(): Decimal - operator fun unaryPlus() = this - - /** - * Sign number of this Decimal, as defined by [BigInteger.signum] - */ - abstract fun signum(): Int - - /** - * Whenever this Decimal is negative (less than zero) - */ - inline val isNegative get() = signum() < 0 - - /** - * Whenever this Decimal is positive (bigger than zero) - */ - inline val isPositive get() = signum() > 0 - - /** - * Whenever this Decimal is zero - */ - inline val isZero get() = signum() == 0 - - abstract val isInfinite: Boolean - abstract val isFinite: Boolean - - /** - * Alias for [coerceAtLeast] with [ZERO] constant, except this method might - * perform faster. - */ - fun moreThanZero(): Decimal { - if (signum() >= 0) - return this - - return Zero - } - - /** - * Alias for [coerceAtMost] with [ZERO] constant, except this method might - * perform faster. - */ - fun lessOrZero(): Decimal { - if (signum() <= 0) - return this - - return Zero - } - - abstract fun toByteArray(): ByteArray - - val absoluteValue: Decimal - get() { - return if (isNegative) { - -this - } else { - this - } - } - - /** - * Truncates fractional part of this Decimal - */ - abstract fun floor(): Decimal - - abstract fun toString(decimals: Int): String - override fun toString(): String = toString(-1) - - abstract fun toBigDecmial(): BigDecimal - - fun percentage(divisor: Decimal): Float { - if (isZero || divisor.isZero) return 0f - - if (this >= divisor) - return 1f - else if (this <= FLOAT_MAX_VALUE && divisor <= FLOAT_MAX_VALUE) - return (toDouble() / divisor.toDouble()).toFloat() - else if (divisor === PositiveInfinity || divisor === NegativeInfinity) - return 0f - - return toBigDecmial().divide(divisor.toBigDecmial(), PERCENTAGE_CONTEXT).toFloat() - } - - private class Regular(val mag: BigInteger, marker: Nothing?) : Decimal() { - constructor(value: BigInteger) : this(value * PRECISION_POW_BI, null) - constructor(value: BigDecimal) : this(value.setScale(PRECISION, RoundingMode.HALF_UP).unscaledValue(), null) - constructor(value: Float) : this(BigDecimal.valueOf(value.toDouble())) - constructor(value: Double) : this(BigDecimal(value)) - constructor(value: String) : this(BigDecimal(value)) - - override val isInfinite: Boolean - get() = false - override val isFinite: Boolean - get() = true - - private var _whole: BigInteger? = null - private var _fractional: BigInteger? = null - - private fun computeWholeFractional(): BigInteger { - val (a, b) = mag.divideAndRemainder(PRECISION_POW_BI) - _whole = a - _fractional = b - return a - } - - override val whole: BigInteger get() { - return _whole ?: computeWholeFractional() - } - - override val fractional: BigInteger get() { - if (_fractional == null) computeWholeFractional() - return _fractional!! - } - - override fun toDouble(): Double { - return mag.toDouble() / PRECISION_DOUBLE - } - - override fun toFloat(): Float { - return mag.toFloat() / PRECISION_FLOAT - } - - override fun toByte(): Byte { - return whole.toByte() - } - - override fun toShort(): Short { - return whole.toShort() - } - - override fun signum(): Int { - return mag.signum() - } - - override fun toInt(): Int { - return if (whole > BI_INT_MAX) { - Int.MAX_VALUE - } else if (whole < BI_INT_MIN) { - Int.MIN_VALUE - } else { - whole.toInt() - } - } - - override fun toLong(): Long { - return if (whole > BI_LONG_MAX) { - Long.MAX_VALUE - } else if (whole < BI_LONG_MIN) { - Long.MIN_VALUE - } else { - whole.toLong() - } - } - - override fun compareTo(other: Decimal): Int { - return if (other === Zero) - signum() - else if (other is Regular) - mag.compareTo(other.mag) - else if (other === PositiveInfinity) - -1 - else if (other === NegativeInfinity) - 1 - else - throw RuntimeException("unreachable code") - } - - - override fun plus(other: Decimal): Decimal { - return if (other is Regular) { - raw(mag + other.mag) - } else if (other === Zero) { - this - } else if (other === PositiveInfinity) { - PositiveInfinity - } else if (other === NegativeInfinity) { - NegativeInfinity - } else { - throw RuntimeException("Unreachable code") - } - } - - override fun minus(other: Decimal): Decimal { - return if (other is Regular) { - raw(mag - other.mag) - } else if (other === Zero) { - this - } else if (other === PositiveInfinity) { - NegativeInfinity - } else if (other === NegativeInfinity) { - PositiveInfinity - } else { - throw RuntimeException("Unreachable code") - } - } - - override fun times(other: Decimal): Decimal { - if (other is Regular) { - if (other == ONE) { - return this - } else if (other == MINUS_ONE) { - return raw(-mag) - } - - val result = mag * other.mag - val (a, b) = result.divideAndRemainder(PRECISION_POW_BI) - - return if (b >= PRECISION_POW_BI_HIGH) { - raw(a + BigInteger.ONE) - } else { - raw(a) - } - } else if (other === Zero) { - return Zero - } else if (other === PositiveInfinity) { - return PositiveInfinity - } else if (other === NegativeInfinity) { - return NegativeInfinity - } else { - throw RuntimeException("Unreachable code") - } - } - - override fun div(other: Decimal): Decimal { - if (other is Regular) { - if (other == ONE) { - return this - } else if (other == MINUS_ONE) { - return raw(-mag) - } - - return raw((mag * PRECISION_POW_BI) / other.mag) - } else if (other === Zero) { - throw ArithmeticException("$this / 0") - } else if (other === PositiveInfinity || other === NegativeInfinity) { - return Zero - } else { - throw RuntimeException("Unreachable code") - } - } - - override fun rem(other: Decimal): Decimal { - return if (other is Regular) { - raw(mag % other.mag) - } else if (other === Zero) { - throw ArithmeticException("$this % 0") - } else if (other === PositiveInfinity) { - this - } else if (other === NegativeInfinity) { - -this - } else { - throw RuntimeException("Unreachable code") - } - } - - // Primitive operators - override fun plus(other: Float): Decimal { - if (other == 0f) { - return this - } else if (other.isNaN()) { - throw ArithmeticException("$this + NaN") - } else if (other == Float.POSITIVE_INFINITY) { - return PositiveInfinity - } else if (other == Float.NEGATIVE_INFINITY) { - return NegativeInfinity - } - - return plus(valueOf(other)) - } - - override fun minus(other: Float): Decimal { - if (other == 0f) { - return this - } else if (other.isNaN()) { - throw ArithmeticException("$this - NaN") - } else if (other == Float.POSITIVE_INFINITY) { - return NegativeInfinity - } else if (other == Float.NEGATIVE_INFINITY) { - return PositiveInfinity - } - - return minus(valueOf(other)) - } - - override fun times(other: Float): Decimal { - if (other == 1f) { - return this - } else if (other == 0f) { - return Zero - } else if (other == -1f) { - return -this - } else if (other.isNaN()) { - throw ArithmeticException("$this * NaN") - } else if (other == Float.POSITIVE_INFINITY) { - return if (signum() < 0) NegativeInfinity else PositiveInfinity - } else if (other == Float.NEGATIVE_INFINITY) { - return if (signum() < 0) PositiveInfinity else NegativeInfinity - } - - return times(valueOf(other)) - } - - override fun div(other: Float): Decimal { - if (other == 0f) { - throw ArithmeticException("$this / 0") - } else if (other == 1f) { - return this - } else if (other == -1f) { - return -this - } else if (other.isNaN()) { - throw ArithmeticException("$this / NaN") - } else if (other.isInfinite()) { - return Zero - } - - return div(valueOf(other)) - } - - override fun plus(other: Double): Decimal { - if (other == 0.0) { - return this - } else if (other.isNaN()) { - throw ArithmeticException("$this + NaN") - } else if (other == Double.POSITIVE_INFINITY) { - return PositiveInfinity - } else if (other == Double.NEGATIVE_INFINITY) { - return NegativeInfinity - } - - return plus(valueOf(other)) - } - - override fun minus(other: Double): Decimal { - if (other == 0.0) { - return this - } else if (other.isNaN()) { - throw ArithmeticException("$this - NaN") - } else if (other == Double.POSITIVE_INFINITY) { - return NegativeInfinity - } else if (other == Double.NEGATIVE_INFINITY) { - return PositiveInfinity - } - - return minus(valueOf(other)) - } - - override fun times(other: Double): Decimal { - if (other == 1.0) { - return this - } else if (other == 0.0) { - return Zero - } else if (other == -1.0) { - return -this - } else if (other.isNaN()) { - throw ArithmeticException("$this * NaN") - } else if (other == Double.POSITIVE_INFINITY) { - return if (signum() < 0) NegativeInfinity else PositiveInfinity - } else if (other == Double.NEGATIVE_INFINITY) { - return if (signum() < 0) PositiveInfinity else NegativeInfinity - } - - return times(valueOf(other)) - } - - override fun div(other: Double): Decimal { - if (other == 0.0) { - throw ArithmeticException("$this / zero") - } else if (other == 1.0) { - return this - } else if (other == -1.0) { - return -this - } else if (other.isNaN()) { - throw ArithmeticException("$this / NaN") - } else if (other.isInfinite()) { - return Zero - } - - return div(valueOf(other)) - } - - override fun plus(other: Int): Decimal { - if (other == 0) - return this - - return plus(valueOf(other)) - } - - override fun minus(other: Int): Decimal { - if (other == 0) - return this - - return minus(valueOf(other)) - } - - override fun times(other: Int): Decimal { - if (other == 1) { - return this - } else if (other == 0) { - return Zero - } else if (other == -1) { - return -this - } - - return times(valueOf(other)) - } - - override fun div(other: Int): Decimal { - if (other == 0) { - throw ArithmeticException("$this / 0") - } else if (other == 1) { - return this - } else if (other == -1) { - return -this - } - - return div(valueOf(other)) - } - - override fun plus(other: Long): Decimal { - if (other == 0L) - return this - - return plus(valueOf(other)) - } - - override fun minus(other: Long): Decimal { - if (other == 0L) - return this - - return minus(valueOf(other)) - } - - override fun times(other: Long): Decimal { - if (other == 1L) { - return this - } else if (other == 0L) { - return Zero - } else if (other == -1L) { - return -this - } - - return times(valueOf(other)) - } - - override fun div(other: Long): Decimal { - if (other == 0L) { - throw ArithmeticException("$this / 0") - } else if (other == 1L || isZero) { - return this - } else if (other == -1L) { - return -this - } - - return div(valueOf(other)) - } - - override fun plus(other: BigInteger): Decimal { - if (other == BigInteger.ZERO) - return this - - return plus(valueOf(other)) - } - - override fun minus(other: BigInteger): Decimal { - if (other == BigInteger.ZERO) - return this - - return minus(valueOf(other)) - } - - override fun times(other: BigInteger): Decimal { - if (other == BigInteger.ONE) { - return this - } else if (other.signum() == 0) { - return Zero - } else if (other == BI_MINUS_ONE) { - return -this - } - - return times(valueOf(other)) - } - - override fun div(other: BigInteger): Decimal { - if (other == BigInteger.ZERO) { - throw ArithmeticException("$this / 0") - } else if (other == BigInteger.ONE) { - return this - } else if (other == BI_MINUS_ONE) { - return -this - } - - return div(valueOf(other)) - } - // /Primitive operators - - override fun unaryMinus(): Decimal { - return Regular(-mag, null) - } - - override fun toByteArray(): ByteArray { - val result = mag.toByteArray() - val copy = ByteArray(result.size + 1) - copy[0] = TYPE_NORMAL - result.copyInto(copy, 1) - return copy - } - - override fun floor(): Decimal { - return Regular(whole) - } - - override fun toString(decimals: Int): String { - if (decimals == 0) { - return whole.toString() - } - - if (mag.signum() == 0) { - return if (decimals < 0) { - "0.0" - } else { - "0." + "0".repeat(decimals) - } - } - - var original = mag.toString() - - if (mag.signum() < 0) { - // если у нас отрицательное число - убираем знак минуса - original = original.substring(1) - } - - if (original.length <= PRECISION) { - // если у нас чисто дробное число - дописываем нули в начало - original = "0".repeat(PRECISION - original.length + 1) + original - } - - // теперь у нас беззнаковая строка с нужной длиной - - if (decimals < 0) { - // нам неважно количество знаков после запятой - var result = original.substring(0, original.length - PRECISION) + "." + original.substring(original.length - PRECISION) - - if (mag.signum() < 0) { - result = "-$result" - } - - var pos = result.length - 1 - - while (result[pos] == '0') { - if (result[pos - 1] == '0' || result[pos - 1] != '.') - pos-- - else - break - } - - return result.substring(0, pos + 1) - } else { - // нужно некоторое количество знаков после запятой - val result = original.substring(0, original.length - PRECISION) + "." - var decimalPart = original.substring(original.length - PRECISION) - - if (decimalPart.length < decimals) { - decimalPart += "0".repeat(decimals - decimalPart.length) - } else if (decimalPart.length > decimals) { - decimalPart = decimalPart.substring(0, decimals) - } - - return if (mag.signum() < 0) { - "-$result$decimalPart" - } else { - "$result$decimalPart" - } - } - } - - override fun toBigDecmial(): BigDecimal { - return BigDecimal(mag, PRECISION) - } - - override fun equals(other: Any?): Boolean { - return this === other || other is Regular && mag == other.mag - } - - override fun hashCode(): Int { - return mag.hashCode() - } - } - - private object PositiveInfinity : Decimal() { - private fun readResolve(): Any = PositiveInfinity - - override val isInfinite: Boolean - get() = true - override val isFinite: Boolean - get() = false - - override fun compareTo(other: Decimal): Int { - return if (other === this) 0 else 1 - } - - override fun toByte(): Byte { - return Byte.MAX_VALUE - } - - override fun toDouble(): Double { - return Double.POSITIVE_INFINITY - } - - override fun toFloat(): Float { - return Float.POSITIVE_INFINITY - } - - override fun toInt(): Int { - return Int.MAX_VALUE - } - - override fun toLong(): Long { - return Long.MAX_VALUE - } - - override fun toShort(): Short { - return Short.MAX_VALUE - } - - override val whole: BigInteger - get() = throw UnsupportedOperationException("Attempt to get whole part of positive infinity") - override val fractional: BigInteger - get() = throw UnsupportedOperationException("Attempt to get fractional part of positive infinity") - - override fun plus(other: Decimal): Decimal { - // not very mathematically correct, since - // case "infinity + infinity" with either sign on either side - // is undefined - return this - } - - override fun minus(other: Decimal): Decimal { - // not very mathematically correct, since - // case "infinity - infinity" with either sign on either side - // is undefined - return this - } - - override fun times(other: Decimal): Decimal { - return if (other.signum() == 0) - Zero - else if (other.signum() < 0) - NegativeInfinity - else - this - } - - override fun div(other: Decimal): Decimal { - return if (other.signum() == 0) - throw ArithmeticException("Attempt to divide positive infinity by zero") - else if (other === this) - throw ArithmeticException("Dividing positive infinity by itself is undefined") - else if (other === NegativeInfinity) - throw ArithmeticException("Dividing positive infinity by negative infinity is undefined") - else if (other.signum() < 0) - NegativeInfinity - else - this - } - - override fun rem(other: Decimal): Decimal { - return if (other.signum() == 0) - throw ArithmeticException("Attempt to remainder divide positive infinity by zero") - else if (other.signum() < 0) - NegativeInfinity - else - this - } - - override fun plus(other: Float): Decimal { - return this - } - - override fun minus(other: Float): Decimal { - return this - } - - override fun times(other: Float): Decimal { - return if (other == 0f) - Zero - else if (other < 0f) - NegativeInfinity - else - PositiveInfinity - } - - override fun div(other: Float): Decimal { - return if (other == 0f) - throw ArithmeticException("Attempt to divide positive infinity by zero") - else if (other < 0f) - NegativeInfinity - else - PositiveInfinity - } - - override fun plus(other: Double): Decimal { - return this - } - - override fun minus(other: Double): Decimal { - return this - } - - override fun times(other: Double): Decimal { - return if (other == 0.0) - Zero - else if (other < 0.0) - NegativeInfinity - else - PositiveInfinity - } - - override fun div(other: Double): Decimal { - return if (other == 0.0) - throw ArithmeticException("Attempt to divide positive infinity by zero") - else if (other < 0.0) - NegativeInfinity - else - PositiveInfinity - } - - override fun plus(other: Int): Decimal { - return this - } - - override fun minus(other: Int): Decimal { - return this - } - - override fun times(other: Int): Decimal { - return if (other == 0) - Zero - else if (other < 0) - NegativeInfinity - else - PositiveInfinity - } - - override fun div(other: Int): Decimal { - return if (other == 0) - throw ArithmeticException("Attempt to divide positive infinity by zero") - else if (other < 0) - NegativeInfinity - else - PositiveInfinity - } - - override fun plus(other: Long): Decimal { - return this - } - - override fun minus(other: Long): Decimal { - return this - } - - override fun times(other: Long): Decimal { - return if (other == 0L) - Zero - else if (other < 0L) - NegativeInfinity - else - PositiveInfinity - } - - override fun div(other: Long): Decimal { - return if (other == 0L) - throw ArithmeticException("Attempt to divide positive infinity by zero") - else if (other < 0L) - NegativeInfinity - else - PositiveInfinity - } - - override fun plus(other: BigInteger): Decimal { - return this - } - - override fun minus(other: BigInteger): Decimal { - return this - } - - override fun times(other: BigInteger): Decimal { - return if (other.signum() == 0) - Zero - else if (other.signum() < 0) - NegativeInfinity - else - PositiveInfinity - } - - override fun div(other: BigInteger): Decimal { - return if (other.signum() == 0) - throw ArithmeticException("Attempt to divide positive infinity by zero") - else if (other.signum() < 0) - NegativeInfinity - else - PositiveInfinity - } - - override fun unaryMinus(): Decimal { - return NegativeInfinity - } - - override fun signum(): Int { - return 1 - } - - override fun toByteArray(): ByteArray { - return byteArrayOf(TYPE_POSITIVE_INFINITY) - } - - override fun floor(): Decimal { - return this - } - - override fun toString(decimals: Int): String { - return "+Infinity" - } - - override fun toBigDecmial(): BigDecimal { - throw UnsupportedOperationException("Unable to construct BigDecimal of positive infinity") - } - } - - private object NegativeInfinity : Decimal() { - private fun readResolve(): Any = NegativeInfinity - - override val isInfinite: Boolean - get() = true - override val isFinite: Boolean - get() = false - - override fun compareTo(other: Decimal): Int { - return if (other === this) 0 else -1 - } - - override fun toByte(): Byte { - return Byte.MIN_VALUE - } - - override fun toDouble(): Double { - return Double.NEGATIVE_INFINITY - } - - override fun toFloat(): Float { - return Float.NEGATIVE_INFINITY - } - - override fun toInt(): Int { - return Int.MIN_VALUE - } - - override fun toLong(): Long { - return Long.MIN_VALUE - } - - override fun toShort(): Short { - return Short.MIN_VALUE - } - - override val whole: BigInteger - get() = throw UnsupportedOperationException("Attempt to get whole part of negative infinity") - override val fractional: BigInteger - get() = throw UnsupportedOperationException("Attempt to get fractional part of negative infinity") - - override fun plus(other: Decimal): Decimal { - return this - } - - override fun minus(other: Decimal): Decimal { - return this - } - - override fun times(other: Decimal): Decimal { - return if (other.signum() == 0) - Zero - else if (other.signum() < 0) - PositiveInfinity - else - this - } - - override fun div(other: Decimal): Decimal { - return if (other.signum() == 0) - throw ArithmeticException("Attempt to divide negative infinity by zero") - else if (other === this) - throw ArithmeticException("Dividing negative infinity by itself is undefined") - else if (other === PositiveInfinity) - throw ArithmeticException("Dividing negative infinity by positive infinity is undefined") - else if (other.signum() < 0) - PositiveInfinity - else - this - } - - override fun rem(other: Decimal): Decimal { - return if (other.signum() == 0) - throw ArithmeticException("Attempt to remainder divide negative infinity by zero") - else if (other.signum() < 0) - PositiveInfinity - else - this - } - - override fun plus(other: Float): Decimal { - return this - } - - override fun minus(other: Float): Decimal { - return this - } - - override fun times(other: Float): Decimal { - return if (other == 0f) - Zero - else if (other < 0f) - PositiveInfinity - else - this - } - - override fun div(other: Float): Decimal { - return if (other == 0f) - throw ArithmeticException("Attempt to divide negative negative by zero") - else if (other < 0f) - PositiveInfinity - else - this - } - - override fun plus(other: Double): Decimal { - return this - } - - override fun minus(other: Double): Decimal { - return this - } - - override fun times(other: Double): Decimal { - return if (other == 0.0) - Zero - else if (other < 0.0) - PositiveInfinity - else - this - } - - override fun div(other: Double): Decimal { - return if (other == 0.0) - throw ArithmeticException("Attempt to divide negative infinity by zero") - else if (other < 0.0) - PositiveInfinity - else - this - } - - override fun plus(other: Int): Decimal { - return this - } - - override fun minus(other: Int): Decimal { - return this - } - - override fun times(other: Int): Decimal { - return if (other == 0) - Zero - else if (other < 0) - PositiveInfinity - else - this - } - - override fun div(other: Int): Decimal { - return if (other == 0) - throw ArithmeticException("Attempt to divide negative infinity by zero") - else if (other < 0) - PositiveInfinity - else - this - } - - override fun plus(other: Long): Decimal { - return this - } - - override fun minus(other: Long): Decimal { - return this - } - - override fun times(other: Long): Decimal { - return if (other == 0L) - Zero - else if (other < 0L) - PositiveInfinity - else - this - } - - override fun div(other: Long): Decimal { - return if (other == 0L) - throw ArithmeticException("Attempt to divide negative infinity by zero") - else if (other < 0L) - PositiveInfinity - else - this - } - - override fun plus(other: BigInteger): Decimal { - return this - } - - override fun minus(other: BigInteger): Decimal { - return this - } - - override fun times(other: BigInteger): Decimal { - return if (other.signum() == 0) - Zero - else if (other.signum() < 0) - PositiveInfinity - else - this - } - - override fun div(other: BigInteger): Decimal { - return if (other.signum() == 0) - throw ArithmeticException("Attempt to divide negative infinity by zero") - else if (other.signum() < 0) - PositiveInfinity - else - this - } - - override fun unaryMinus(): Decimal { - return PositiveInfinity - } - - override fun signum(): Int { - return -1 - } - - override fun toByteArray(): ByteArray { - return byteArrayOf(TYPE_NEGATIVE_INFINITY) - } - - override fun floor(): Decimal { - return this - } - - override fun toString(decimals: Int): String { - return "-Infinity" - } - - override fun toBigDecmial(): BigDecimal { - throw UnsupportedOperationException("Unable to construct BigDecimal of negative infinity") - } - } - - private object Zero : Decimal() { - private fun readResolve(): Any = Zero - - override val isInfinite: Boolean - get() = false - override val isFinite: Boolean - get() = true - - override fun compareTo(other: Decimal): Int { - return -other.signum() - } - - override fun toByte(): Byte { - return 0 - } - - override fun toDouble(): Double { - return 0.0 - } - - override fun toFloat(): Float { - return 0f - } - - override fun toInt(): Int { - return 0 - } - - override fun toLong(): Long { - return 0L - } - - override fun toShort(): Short { - return 0 - } - - override val whole: BigInteger - get() = BigInteger.ZERO - override val fractional: BigInteger - get() = BigInteger.ZERO - - override fun plus(other: Decimal): Decimal { - return other - } - - override fun minus(other: Decimal): Decimal { - return -other - } - - override fun times(other: Decimal): Decimal { - return this - } - - override fun div(other: Decimal): Decimal { - if (other === this) - throw ArithmeticException("0 / 0") - else - return this - } - - override fun rem(other: Decimal): Decimal { - if (other === this) - throw ArithmeticException("0 % 0") - else - return this - } - - override fun plus(other: Float): Decimal { - return valueOf(other) - } - - override fun minus(other: Float): Decimal { - return valueOf(-other) - } - - override fun times(other: Float): Decimal { - return this - } - - override fun div(other: Float): Decimal { - if (other == 0f) - throw ArithmeticException("0 / 0") - - return this - } - - override fun plus(other: Double): Decimal { - return valueOf(other) - } - - override fun minus(other: Double): Decimal { - return valueOf(-other) - } - - override fun times(other: Double): Decimal { - return this - } - - override fun div(other: Double): Decimal { - if (other == 0.0) - throw ArithmeticException("0 / 0") - - return this - } - - override fun plus(other: Int): Decimal { - return valueOf(other) - } - - override fun minus(other: Int): Decimal { - return valueOf(-other) - } - - override fun times(other: Int): Decimal { - return this - } - - override fun div(other: Int): Decimal { - if (other == 0) - throw ArithmeticException("0 / 0") - - return this - } - - override fun plus(other: Long): Decimal { - return valueOf(other) - } - - override fun minus(other: Long): Decimal { - return valueOf(-other) - } - - override fun times(other: Long): Decimal { - return this - } - - override fun div(other: Long): Decimal { - if (other == 0L) - throw ArithmeticException("0 / 0") - - return this - } - - override fun plus(other: BigInteger): Decimal { - return valueOf(other) - } - - override fun minus(other: BigInteger): Decimal { - return valueOf(-other) - } - - override fun times(other: BigInteger): Decimal { - return this - } - - override fun div(other: BigInteger): Decimal { - if (other == BigInteger.ZERO) - throw ArithmeticException("0 / 0") - - return this - } - - override fun unaryMinus(): Decimal { - return this - } - - override fun signum(): Int { - return 0 - } - - override fun toByteArray(): ByteArray { - return byteArrayOf(TYPE_ZERO) - } - - override fun floor(): Decimal { - return this - } - - override fun toString(decimals: Int): String { - if (decimals == 0) - return "0" - else if (decimals < 0) - return "0.0" - else - return "0." + "0".repeat(decimals) - } - - override fun toBigDecmial(): BigDecimal { - return BigDecimal.ZERO - } - } - - @Suppress("unused") - companion object { - /** - * Amount of digits after fixed point, in 10 radix - */ - const val PRECISION = 11 - - const val TYPE_ZERO: Byte = 0 - const val TYPE_NORMAL: Byte = 1 - const val TYPE_POSITIVE_INFINITY: Byte = 2 - const val TYPE_NEGATIVE_INFINITY: Byte = 3 - - @JvmField - val PRECISION_POW_BI: BigInteger = BigInteger("1" + "0".repeat(PRECISION)) - @JvmField - val PRECISION_DOUBLE = PRECISION_POW_BI.toDouble() - @JvmField - val PRECISION_FLOAT = PRECISION_POW_BI.toFloat() - @JvmField - val PRECISION_POW_BI_NEGATIVE: BigInteger = -PRECISION_POW_BI - @JvmField - val PRECISION_POW_BI_HIGH: BigInteger = PRECISION_POW_BI / BigInteger.TWO - - private const val cacheSize = 16384 - private const val cacheSizeL = cacheSize.toLong() - - private val cache = Array(cacheSize) { Regular(BigInteger.valueOf(it.toLong() - cacheSize / 2)) } - - init { - check(cache[cacheSize / 2].signum() == 0) - cache[cacheSize / 2] = Zero - } - - /** - * Returns pooled value if present, otherwise constructs new object - */ - @JvmStatic - fun valueOf(value: Int): Decimal { - if (value in (cacheSize / -2) until cacheSize / 2) { - return cache[value + cacheSize / 2] - } - - return Regular(BigInteger.valueOf(value.toLong())) - } - - /** - * Returns pooled value if present, otherwise constructs new object - */ - @JvmStatic - fun valueOf(value: Long): Decimal { - if (value in (cacheSizeL / -2L) until cacheSizeL / 2L) { - return cache[value.toInt() + cacheSize / 2] - } - - return Regular(BigInteger.valueOf(value)) - } - - /** - * Returns pooled value if present, otherwise constructs new object - */ - @JvmStatic - fun valueOf(value: Short) = valueOf(value.toInt()) - - /** - * Returns pooled value if present, otherwise constructs new object - */ - @JvmStatic - fun valueOf(value: Byte) = valueOf(value.toInt()) - - @JvmStatic fun valueOf(value: BigInteger): Decimal { - return if (value.signum() == 0) { - Zero - } else { - Regular(value) - } - } - - @JvmStatic fun valueOf(value: BigDecimal): Decimal { - return if (value.signum() == 0) { - Zero - } else { - Regular(value) - } - } - - @JvmStatic fun valueOf(value: String): Decimal { - if (value == "0") { - return Zero - } else { - val lower = value.lowercase() - - // why not - if (lower.startsWith("+inf") || lower.startsWith("inf") || lower == "∞" || lower == "+∞") { - return PositiveInfinity - } else if (lower.startsWith("-inf") || lower == "-∞") { - return NegativeInfinity - } else { - val result = Regular(value) - if (result.signum() == 0) return Zero - return result - } - } - } - - @JvmStatic fun valueOf(value: Float): Decimal { - return if (value == 0f) { - Zero - } else if (value == Float.POSITIVE_INFINITY) { - PositiveInfinity - } else if (value == Float.NEGATIVE_INFINITY) { - NegativeInfinity - } else { - Regular(value) - } - } - - @JvmStatic fun valueOf(value: Double): Decimal { - return if (value == 0.0) { - Zero - } else if (value == Double.POSITIVE_INFINITY) { - PositiveInfinity - } else if (value == Double.NEGATIVE_INFINITY) { - NegativeInfinity - } else { - Regular(value) - } - } - - @JvmStatic - fun fromByteArray(input: ByteArray): Decimal { - return if (input.isEmpty()) { - Zero - } else { - return when (input[0]) { - TYPE_NORMAL -> raw(BigInteger(input.copyOfRange(1, input.size))) - TYPE_NEGATIVE_INFINITY -> if (input.size == 1) NegativeInfinity else Zero - TYPE_POSITIVE_INFINITY -> if (input.size == 1) PositiveInfinity else Zero - // TYPE_ZERO -> Zero - else -> Zero - } - } - } - - /** - * Takes in [value] as-is and constructs [Decimal] out of it ([value] is treated as already scaled by [PRECISION]) - */ - @JvmStatic - fun raw(value: BigInteger): Decimal { - return if (value.signum() == 0) { - Zero - } else { - Regular(value, null) - } - } - - @JvmField val POSITIVE_INFINITY: Decimal = PositiveInfinity - @JvmField val NEGATIVE_INFINITY: Decimal = NegativeInfinity - @JvmField val ZERO: Decimal = Zero - @JvmField val ONE = valueOf(1) - @JvmField val TWO = valueOf(2) - @JvmField val TEN = valueOf(10) - @JvmField val MINUS_ONE = valueOf(-1) - @JvmField val MINUS_TWO = valueOf(-2) - @JvmField val MINUS_TEN = valueOf(-10) - @JvmField val ONE_TENTH = valueOf("0.1") - @JvmField val ONE_QUARTER = valueOf("0.25") - @JvmField val ONE_EIGHTH = valueOf("0.125") - @JvmField val ONE_HALF = valueOf("0.5") - @JvmField val MINUS_ONE_TENTH = valueOf("-0.1") - @JvmField val MINUS_ONE_EIGHTH = valueOf("-0.125") - @JvmField val MINUS_ONE_QUARTER = valueOf("-0.25") - @JvmField val MINUS_ONE_HALF = valueOf("-0.5") - - @JvmField val INT_MAX_VALUE: Decimal = Regular(BI_INT_MAX) - @JvmField val INT_MIN_VALUE: Decimal = Regular(BI_INT_MIN) - @JvmField val LONG_MAX_VALUE: Decimal = Regular(BI_LONG_MAX) - @JvmField val LONG_MIN_VALUE: Decimal = Regular(BI_LONG_MIN) - - @JvmField val FLOAT_MAX_VALUE: Decimal = Regular(BI_FLOAT_MAX) - @JvmField val FLOAT_MIN_VALUE: Decimal = Regular(BI_FLOAT_MIN) - @JvmField val DOUBLE_MAX_VALUE: Decimal = Regular(BI_DOUBLE_MAX) - @JvmField val DOUBLE_MIN_VALUE: Decimal = Regular(BI_DOUBLE_MIN) - } -} - -fun Float.toDecimal() = Decimal(this) -fun Double.toDecimal() = Decimal(this) -fun Int.toDecimal() = Decimal(this) -fun Byte.toDecimal() = Decimal(this) -fun Short.toDecimal() = Decimal(this) -fun Long.toDecimal() = Decimal(this) -fun Decimal.toDecimal() = this