From ccb80c03862daf05d6972a8e37b0006c475bd71d Mon Sep 17 00:00:00 2001 From: Alexandre Mommers Date: Tue, 8 Aug 2023 01:52:47 +0200 Subject: [PATCH] remove kbignum --- kbignum/.gitignore | 10 - kbignum/LICENSE | 21 - kbignum/README.md | 11 - kbignum/build.gradle.kts | 10 - kbignum/gradle.properties | 1 - .../kotlin/korlibs/bignumber/BigExt.kt | 21 - .../kotlin/korlibs/bignumber/BigInt.kt | 171 ----- .../korlibs/bignumber/BigIntException.kt | 12 - .../kotlin/korlibs/bignumber/BigNum.kt | 152 ---- .../kotlin/korlibs/bignumber/CommonBigInt.kt | 698 ------------------ .../korlibs/bignumber/internal/IntExt.kt | 13 - .../bignumber/internal/progressionUtil.kt | 27 - .../korlibs/bignumber/ranges/BigIntRange.kt | 109 --- .../bignumber/ranges/ClosedBigNumRange.kt | 34 - .../bignumber/BigIntProgressionTest.kt | 32 - .../korlibs/bignumber/BigIntRangeTest.kt | 35 - .../kotlin/korlibs/bignumber/BigIntTest.kt | 361 --------- .../kotlin/korlibs/bignumber/BigNumTest.kt | 189 ----- .../kotlin/korlibs/bignumber/RangesTest.kt | 19 - .../korlibs/bignumber/internal/IntExtTest.kt | 41 - .../bignumber/internal/ProgressionUtilTest.kt | 17 - .../kotlin/korlibs/bignumber/BigIntJs.kt | 83 --- .../korlibs/bignumber/ext/NativeJsBigInt.kt | 22 - .../kotlin/korlibs/bignumber/BigIntJvm.kt | 72 -- .../bignumber/BigIntCompareWithJVMTest.kt | 249 ------- .../kotlin/korlibs/bignumber/BigIntNative.kt | 3 - .../kotlin/korlibs/bignumber/BigIntNative.kt | 3 - settings.gradle.kts | 1 - 28 files changed, 2417 deletions(-) delete mode 100644 kbignum/.gitignore delete mode 100644 kbignum/LICENSE delete mode 100644 kbignum/README.md delete mode 100644 kbignum/build.gradle.kts delete mode 100644 kbignum/gradle.properties delete mode 100644 kbignum/src/commonMain/kotlin/korlibs/bignumber/BigExt.kt delete mode 100644 kbignum/src/commonMain/kotlin/korlibs/bignumber/BigInt.kt delete mode 100644 kbignum/src/commonMain/kotlin/korlibs/bignumber/BigIntException.kt delete mode 100644 kbignum/src/commonMain/kotlin/korlibs/bignumber/BigNum.kt delete mode 100644 kbignum/src/commonMain/kotlin/korlibs/bignumber/CommonBigInt.kt delete mode 100644 kbignum/src/commonMain/kotlin/korlibs/bignumber/internal/IntExt.kt delete mode 100644 kbignum/src/commonMain/kotlin/korlibs/bignumber/internal/progressionUtil.kt delete mode 100644 kbignum/src/commonMain/kotlin/korlibs/bignumber/ranges/BigIntRange.kt delete mode 100644 kbignum/src/commonMain/kotlin/korlibs/bignumber/ranges/ClosedBigNumRange.kt delete mode 100644 kbignum/src/commonTest/kotlin/korlibs/bignumber/BigIntProgressionTest.kt delete mode 100644 kbignum/src/commonTest/kotlin/korlibs/bignumber/BigIntRangeTest.kt delete mode 100644 kbignum/src/commonTest/kotlin/korlibs/bignumber/BigIntTest.kt delete mode 100644 kbignum/src/commonTest/kotlin/korlibs/bignumber/BigNumTest.kt delete mode 100644 kbignum/src/commonTest/kotlin/korlibs/bignumber/RangesTest.kt delete mode 100644 kbignum/src/commonTest/kotlin/korlibs/bignumber/internal/IntExtTest.kt delete mode 100644 kbignum/src/commonTest/kotlin/korlibs/bignumber/internal/ProgressionUtilTest.kt delete mode 100644 kbignum/src/jsMain/kotlin/korlibs/bignumber/BigIntJs.kt delete mode 100644 kbignum/src/jsMain/kotlin/korlibs/bignumber/ext/NativeJsBigInt.kt delete mode 100644 kbignum/src/jvmAndroidMain/kotlin/korlibs/bignumber/BigIntJvm.kt delete mode 100644 kbignum/src/jvmTest/kotlin/korlibs/bignumber/BigIntCompareWithJVMTest.kt delete mode 100644 kbignum/src/nativeMain/kotlin/korlibs/bignumber/BigIntNative.kt delete mode 100644 kbignum/src/wasmMain/kotlin/korlibs/bignumber/BigIntNative.kt diff --git a/kbignum/.gitignore b/kbignum/.gitignore deleted file mode 100644 index ec363beefc..0000000000 --- a/kbignum/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -/.idea -/.gradle -/build -/out -/classes -/web -*.ipr -*.iws -*.iml -/local.properties diff --git a/kbignum/LICENSE b/kbignum/LICENSE deleted file mode 100644 index 74b774f883..0000000000 --- a/kbignum/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Carlos Ballesteros Velasco - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/kbignum/README.md b/kbignum/README.md deleted file mode 100644 index 088bcb5eec..0000000000 --- a/kbignum/README.md +++ /dev/null @@ -1,11 +0,0 @@ -

KBigNum

- - -

- Build Status - Maven Central - Discord -

- - -### Full Documentation: \ No newline at end of file diff --git a/kbignum/build.gradle.kts b/kbignum/build.gradle.kts deleted file mode 100644 index a78178a644..0000000000 --- a/kbignum/build.gradle.kts +++ /dev/null @@ -1,10 +0,0 @@ -import korlibs.applyProjectProperties - -description = "Big Integers and decimals in Kotlin Common" - -project.extensions.extraProperties.properties.apply { - applyProjectProperties("https://github.com/korlibs/korge/main/kbignum","MIT License","https://raw.githubusercontent.com/korlibs/korge/main/kbignum/LICENSE") -} - -dependencies { -} diff --git a/kbignum/gradle.properties b/kbignum/gradle.properties deleted file mode 100644 index 9dc79b5948..0000000000 --- a/kbignum/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -enable.wasm=true diff --git a/kbignum/src/commonMain/kotlin/korlibs/bignumber/BigExt.kt b/kbignum/src/commonMain/kotlin/korlibs/bignumber/BigExt.kt deleted file mode 100644 index dd78fcddff..0000000000 --- a/kbignum/src/commonMain/kotlin/korlibs/bignumber/BigExt.kt +++ /dev/null @@ -1,21 +0,0 @@ -package korlibs.bignumber - -// Big Integer -/** Converts this into a [BigInt] */ -val Long.bi: BigInt get() = BigInt(this) -/** Converts this into a [BigInt] */ -val Int.bi: BigInt get() = BigInt(this) -/** Converts this into a [BigInt] */ -val String.bi: BigInt get() = BigInt(this) -/** Converts this into a [BigInt] using a specific [radix], that is the base to use. radix=10 for decimal, radix=16 for hexadecimal */ -fun String.bi(radix: Int): BigInt = BigInt(this, radix) - -// Big Number -/** Converts this into a [BigNum] */ -val Double.bn: BigNum get() = BigNum("$this") -/** Converts this into a [BigNum] */ -val Long.bn: BigNum get() = BigNum(this.bi, 0) -/** Converts this into a [BigNum] */ -val Int.bn: BigNum get() = BigNum(this.bi, 0) -/** Converts this into a [BigNum] */ -val String.bn: BigNum get() = BigNum(this) diff --git a/kbignum/src/commonMain/kotlin/korlibs/bignumber/BigInt.kt b/kbignum/src/commonMain/kotlin/korlibs/bignumber/BigInt.kt deleted file mode 100644 index f169ce13e3..0000000000 --- a/kbignum/src/commonMain/kotlin/korlibs/bignumber/BigInt.kt +++ /dev/null @@ -1,171 +0,0 @@ -package korlibs.bignumber - -import korlibs.bignumber.ranges.* - -/** - * Represents an arbitrary-sized Big Integer. - */ -interface BigInt : Comparable, BigIntConstructor { - companion object { - val usesNativeImplementation get() = BigInt(0) !is CommonBigInt - - val ZERO = BigInt("0") - val MINUS_ONE = BigInt("-1") - val ONE = BigInt("1") - val TWO = BigInt("2") - val TEN = BigInt("10") - val SMALL = BigInt(UINT16_MASK) - } - - // Checks - /** Returns -1, 0 or +1 depending on the sign of this [BigInt] */ - val signum: Int - /** Determines if this [BigInt] is 0 */ - val isZero get() = signum == 0 - /** Determines if this [BigInt] is not 0 */ - val isNotZero get() = signum != 0 - /** Determines if this [BigInt] is negative */ - val isNegative get() = signum < 0 - /** Determines if this [BigInt] is positive */ - val isPositive get() = signum > 0 - /** Determines if this [BigInt] is either negative or zero (non-positive) */ - val isNegativeOrZero get() = signum <= 0 - /** Determines if this [BigInt] is either positive or zero (non-negative) */ - val isPositiveOrZero get() = signum >= 0 - - // Unary - /** Returns this [BigInt]. A convenience method to make explicit the sign and to have symmetry with [unaryMinus]. */ - operator fun unaryPlus(): BigInt = this - /** Returns a new [BigInt] with its sign changed. In the case of 0, it returns itself. */ - operator fun unaryMinus(): BigInt - /** Returns a new [BigInt] with its bits flipped. 0 converts into 1, and 1 into 0. Equivalent to `-(this + 1)` */ - fun inv(): BigInt - - // Binary - /** Returns this [BigInt] raised to [exponent] : `this ** exponent` */ - infix fun pow(exponent: BigInt): BigInt - /** Returns this [BigInt] raised to [exponent] : `this ** exponent` */ - infix fun pow(exponent: Int): BigInt - - /** Returns a new BigInt with bits combining [this], [other] doing a bitwise `&`/`and` operation. Forces sign to positive. */ - infix fun and(other: BigInt): BigInt - /** Returns a new BigInt with bits combining [this], [other] doing a bitwise `|`/`or` operation. Forces sign to positive. */ - infix fun or(other: BigInt): BigInt - /** Returns a new BigInt with bits combining [this], [other] doing a bitwise `^`/`xor` operation. Forces sign to positive. */ - infix fun xor(other: BigInt): BigInt - - /** Returns a new BigInt with bits from [this] shifted to the left [count]. Equivalent to multiply by 2**[count]. Keeps the sign of [this] */ - infix fun shl(count: Int): BigInt - /** Returns a new BigInt with bits from [this] shifted to the left [count]. Equivalent to divide by 2**[count]. Keeps the sign of [this] */ - infix fun shr(count: Int): BigInt - - /** Returns a new BigInt this [this] + [other] */ - operator fun plus(other: BigInt): BigInt - /** Returns a new BigInt this [this] - [other] */ - operator fun minus(other: BigInt): BigInt - /** Returns a new BigInt this [this] * [other] */ - operator fun times(other: BigInt): BigInt - /** Returns a new BigInt this [this] / [other] */ - operator fun div(other: BigInt): BigInt - /** Returns a new BigInt this [this] % [other] */ - operator fun rem(other: BigInt): BigInt - - // Conversion - /** Converts this number to a [Int]. Throws a [BigIntOverflowException] in the case the number is too big to be stored in an [Int] */ - fun toInt(): Int - /** Converts this number to a [String] using the specified [radix]. The radix is the base to use. 10 for decimal. 16 for hexadecimal. */ - fun toString(radix: Int): String - - // Extra - /** Square of this number. Equivalent [this] * [this], but might be faster in some implementations. */ - fun square(): BigInt = this * this - /** Returns this [BigInt] as positive or zero. Equivalent to `if (isNegative) -this else this` */ - fun abs(): BigInt = if (isNegative) -this else this - /** Returns this + [other] */ - operator fun plus(other: Int): BigInt = this + create(other) - /** Returns this - [other] */ - operator fun minus(other: Int): BigInt = this - create(other) - /** Returns this * [other] */ - operator fun times(other: Int): BigInt = this * create(other) - /** Returns this * [other] */ - operator fun times(other: Long): BigInt = this * create(other) - /** Returns this / [other] */ - operator fun div(other: Int): BigInt = this / create(other) - /** Returns this % [other] */ - operator fun rem(other: Int): BigInt = this % create(other) - - /** Creates a new inclusive [BigIntRange] ranging from [this] to [that] */ - operator fun rangeTo(that: BigInt): BigIntRange = BigIntRange(start = this, endInclusive = that) -} - -interface BigIntCompanion : BigIntConstructor { - operator fun invoke(value: Int) = create(value) - operator fun invoke(value: Long) = create(value) - operator fun invoke(value: String) = create(value) - operator fun invoke(value: String, radix: Int) = create(value, radix) -} - -interface BigIntConstructor { - fun create(value: Int): BigInt - //fun create(value: Long): BigInt = create("$value", 10) // @TODO: Kotlin.JS BUG - fun create(value: Long): BigInt { - if (value.toInt().toLong() == value) return create(value.toInt()) - return create(value.toString(10), 10) - } - // General - fun create(value: String, radix: Int): BigInt { - if (value.isEmpty()) throw BigIntInvalidFormatException("Zero length BigInteger") - if (value.startsWith('-')) return -create(value.substring(1), radix) - if (value == "0") return create(0) - //val wordsRequired = ceil((value.length * log2(radix.toDouble())) / 16.0).toInt() - //val out = UInt16ArrayZeroPad(IntArray(wordsRequired)) - var out = create(0) - - //for (c in value) { - // out *= radix - // out += digit(c, radix) - //} - - var sum = 0 - var mul = 1 - - for (n in 0 until value.length) { - val last = n == value.length - 1 - val c = value[n] - val d = digit(c, radix) - - //UnsignedBigInt.inplaceSmallMulAdd(out, radix, d) - sum *= radix - sum += d - mul *= radix - //if (last || mul * radix > 0x7FFF) { - //if (last || mul * radix >= 0x1FFFFFFF) { - if (last || mul * radix >= 0x1FFFFFF) { - out *= mul - out += sum - sum = 0 - mul = 1 - } - } - return out - } - - fun create(value: String): BigInt { - if (value.startsWith("-")) return -create(value.substring(1)) - return parseWithNumberPrefix(value) { sub, radix -> create(sub, radix) } - } -} - -expect val BigIntNativeFactory: BigIntConstructor - -fun BigInt(value: Int): BigInt = BigIntNativeFactory.create(value) -fun BigInt(value: Long): BigInt = BigIntNativeFactory.create(value) -fun BigInt(value: String, radix: Int): BigInt = BigIntNativeFactory.create(value, radix) -fun BigInt(value: String): BigInt = BigIntNativeFactory.create(value) - -internal fun parseWithNumberPrefix(str: String, gen: (sub: String, radix: Int) -> T): T = when { - str.startsWith("0x") -> gen(str.substring(2), 16) - str.startsWith("0o") -> gen(str.substring(2), 8) - str.startsWith("0b") -> gen(str.substring(2), 2) - else -> gen(str, 10) -} diff --git a/kbignum/src/commonMain/kotlin/korlibs/bignumber/BigIntException.kt b/kbignum/src/commonMain/kotlin/korlibs/bignumber/BigIntException.kt deleted file mode 100644 index 1a4c58408a..0000000000 --- a/kbignum/src/commonMain/kotlin/korlibs/bignumber/BigIntException.kt +++ /dev/null @@ -1,12 +0,0 @@ -package korlibs.bignumber - -/** A generic [BigInt] exception */ -open class BigIntException(message: String) : Throwable(message) -/** A [BigInt] exception thrown when an invalid String value is provided while parsing */ -open class BigIntInvalidFormatException(message: String) : BigIntException(message) -/** A [BigInt] exception thrown when trying to divide by zero */ -open class BigIntDivisionByZeroException() : BigIntException("Division by zero") -/** A [BigInt] exception thrown when an overflow operation occurs, like for example when trying to convert a too big [BigInt] into an [Int] */ -open class BigIntOverflowException(message: String) : BigIntException(message) -/** A [BigInt] exception thrown when doing a `pow` operation with a negative exponent */ -open class BigIntNegativeExponentException() : BigIntOverflowException("Negative exponent") diff --git a/kbignum/src/commonMain/kotlin/korlibs/bignumber/BigNum.kt b/kbignum/src/commonMain/kotlin/korlibs/bignumber/BigNum.kt deleted file mode 100644 index bae9131ce0..0000000000 --- a/kbignum/src/commonMain/kotlin/korlibs/bignumber/BigNum.kt +++ /dev/null @@ -1,152 +0,0 @@ -package korlibs.bignumber - -import korlibs.bignumber.ranges.* -import kotlin.math.* - -/** - * Represents a [BigNum], - * a numeric value with decimal places that is exact. - * - * There are no precision issues like happens with [Float] or [Double] floating point types. - */ -class BigNum(val int: BigInt, val scale: Int) : Comparable { - init { - //println("BigNum($int, $scale) == $this") - } - - companion object { - /** Represents 0.0 as a [BigNum] */ - val ZERO = BigNum(BigInt(0), 0) - /** Represents 1.0 as a [BigNum] */ - val ONE = BigNum(BigInt(1), 0) - /** Represents 2.0 as a [BigNum] */ - val TWO = BigNum(BigInt(2), 0) - - /** Creates a [BigNum] from a string [str] */ - operator fun invoke(str: String): BigNum { - val str = str.lowercase() - //val ss = if (str.contains('.')) str.trimEnd('0') else str - val exponentPartStr = str.substringAfter('e', "").takeIf { it.isNotEmpty() }?.trimStart('+') - val ss = str.substringBefore('e') - val point = ss.indexOf('.') - val strBase = ss.replace(".", "") - val exponent = exponentPartStr?.toInt() ?: 0 - val int = BigInt(strBase) - return if (point < 0) { - BigNum(int, -exponent) - } else { - BigNum(int, ss.length - point - 1 - exponent) - } - } - } - - /** - * Converts the internal scale of this BigNum to [otherScale] while keeping the same value. - * - * For example: - * ```kotlin - * assertEquals("0.0010", "0.001".bn.convertToScale(4).toString()) - * ``` - */ - fun convertToScale(otherScale: Int): BigNum = when { - this.scale == otherScale -> this - otherScale > this.scale -> BigNum(int * (10.bi pow (otherScale - this.scale)), otherScale) - else -> BigNum(int / (10.bi pow (this.scale - otherScale)), otherScale) - } - - /** Performs this + [other] returning a [BigNum], if the scale is different for both numbers, it finds a common one */ - operator fun plus(other: BigNum): BigNum = binary(other, BigInt::plus) - /** Performs this - [other] returning a [BigNum], if the scale is different for both numbers, it finds a common one */ - operator fun minus(other: BigNum): BigNum = binary(other, BigInt::minus) - /** Performs this * [other] returning a [BigNum], the scale ends being the sum of both scales */ - operator fun times(other: BigNum): BigNum = - BigNum(this.int * other.int, this.scale + other.scale) - - /** Performs this / [other] returning a [BigNum] */ - //operator fun div(other: BigNum): BigNum = div(other, other.int.significantBits / 2) - operator fun div(other: BigNum): BigNum = div(other, 0) - - /** Performs this / [other] returning a [BigNum] using a specific [precision] */ - fun div(other: BigNum, precision: Int): BigNum { - val scale = (10.bi pow (other.scale + precision)) - val li = this.int * scale - val ri = other.int - val res = li / ri - return BigNum(res, this.scale) * BigNum(1.bi, precision) - } - - /** Performs this ** [exponent] */ - infix fun pow(exponent: Int) = pow(exponent, 32) - - /** Performs this ** [exponent] with a specific [precision] */ - fun pow(exponent: Int, precision: Int): BigNum { - //if (exponent < 0) return ONE.div(this.pow(-exponent, precision), precision) - if (exponent < 0) return ONE.div(this.pow(-exponent, precision), 0) - var result = ONE - var base = this - var exp = exponent - while (exp != 0) { - if ((exp and 1) != 0) result *= base - exp = exp shr 1 - base *= base - } - return result - } - - override operator fun compareTo(other: BigNum): Int { - val commonScale = this.commonScale(other) - return this.convertToScale(commonScale).int.compareTo(other.convertToScale(commonScale).int) - } - - /** Creates a [ClosedBigNumRange] between this and [that] */ - operator fun rangeTo(that: BigNum): ClosedBigNumRange = ClosedBigNumRange( - start = this, - endInclusive = that - ) - - override fun hashCode(): Int = int.hashCode() + 3 * scale.hashCode() - override fun equals(other: Any?): Boolean = (other is BigNum) && this.compareTo(other) == 0 - - private fun commonScale(other: BigNum) = max(this.scale, other.scale) - - private inline fun binary(other: BigNum, callback: (l: BigInt, r: BigInt) -> BigInt): BigNum { - val commonScale = this.commonScale(other) - val l = this.convertToScale(commonScale) - val r = other.convertToScale(commonScale) - val li = l.int - val ri = r.int - return BigNum(callback(li, ri), commonScale) - } - - override fun toString(): String { - val isNegative = int.isNegative - val out = "${int.abs()}" - val pos = out.length - scale - val negativePart = if (isNegative) "-" else "" - return negativePart + when { - pos <= 0 -> "0." + "0".repeat(-pos) + out - pos >= out.length -> out + "0".repeat(pos - out.length) - else -> (out.substring(0, pos) + "." + out.substring(pos)).trimEnd('.') - } - } - - /** Converts this [BigInt] effectively losing the decimal places */ - fun toBigInt(): BigInt = convertToScale(0).int - /** Converts this [BigInt] doing flooring when there are decimals */ - fun toBigIntFloor(): BigInt = toBigInt() - /** Converts this [BigInt] doing ceiling when there are decimals */ - fun toBigIntCeil(): BigInt { - val it = this.toBigInt() - val decimal = decimalPart - return if (decimal.isZero) it else (it + 1.bi) - } - /** Converts this [BigInt] doing rounding when there are decimals */ - fun toBigIntRound(): BigInt { - val firstDigit = decimalPart / 10.bi.pow(scale - 1) - return if (firstDigit.toInt() >= 5) toBigIntCeil() else toBigIntFloor() - } - - /** Returns the decimal part as a [BigInt] of this BigNum so for `1.9123.bn` it will return `9123.bi` */ - val decimalPart: BigInt - get() = int % 10.bi.pow(scale) -} diff --git a/kbignum/src/commonMain/kotlin/korlibs/bignumber/CommonBigInt.kt b/kbignum/src/commonMain/kotlin/korlibs/bignumber/CommonBigInt.kt deleted file mode 100644 index cf07440f43..0000000000 --- a/kbignum/src/commonMain/kotlin/korlibs/bignumber/CommonBigInt.kt +++ /dev/null @@ -1,698 +0,0 @@ -package korlibs.bignumber - -import korlibs.bignumber.internal.* -import kotlin.math.* -import kotlin.time.* - -/** - * @TODO: Use JVM BigInteger and JS BigInt - */ -class CommonBigInt private constructor(val data: UInt16ArrayZeroPad, override val signum: Int, var dummy: Boolean) : BigInt, BigIntConstructor by CommonBigInt { - val isOne get() = isSmall && this == ONE - val isSmall get() = data.size <= 1 - val maxBits get() = data.size * CHUNK_BITS - val significantBits get() = maxBits - leadingZeros() - - companion object : BigIntCompanion { - internal const val CHUNK_BITS = Short.SIZE_BITS // UInt16ArrayZeroPad - - val ZERO = CommonBigInt(uint16ArrayZeroPadOf(), 0, true) - val MINUS_ONE = CommonBigInt(uint16ArrayZeroPadOf(1), -1, true) - val ONE = CommonBigInt(uint16ArrayZeroPadOf(1), 1, true) - val TWO = CommonBigInt(uint16ArrayZeroPadOf(2), 1, true) - val TEN = CommonBigInt(uint16ArrayZeroPadOf(10), 1, true) - val SMALL = CommonBigInt(uint16ArrayZeroPadOf(UINT16_MASK), 1, true) - - operator fun invoke(data: UInt16ArrayZeroPad, signum: Int): CommonBigInt { - // Trim leading zeros - var maxN = 0 - for (n in data.size - 1 downTo 0) { - if (data[n] != 0) { - maxN = n + 1 - break - } - } - - if (maxN == 0) return ZERO - return CommonBigInt(data.copyOf(maxN), signum, false) - } - - override fun create(value: Int): CommonBigInt = when (value) { - -1 -> MINUS_ONE - 0 -> ZERO - 1 -> ONE - 2 -> TWO - else -> { - val magnitude = value.toLong().absoluteValue - CommonBigInt( - uint16ArrayZeroPadOf( - (magnitude ushr 0).toInt(), - (magnitude ushr 16).toInt() - ), value.sign - ) - } - } - //if (value == 0) return CommonBigInt(uint16ArrayZeroPadOf(), 0, true) - - override operator fun invoke(value: Int): CommonBigInt = create(value) - override operator fun invoke(value: Long): CommonBigInt = create(value) as CommonBigInt - override operator fun invoke(value: String): CommonBigInt = create(value) as CommonBigInt - override operator fun invoke(value: String, radix: Int): CommonBigInt = create(value, radix) as CommonBigInt - } - - fun countBits(): Int { - var count = 0 - for (n in 0 until data.size) count += data[n].bitCount() - return count - } - - /** Number of leadingZeros with the size of [maxBits] */ - fun leadingZeros(): Int { - if (isZero) return maxBits - for (n in 0 until data.size) { - val dataN = data[data.size - n - 1] - if (dataN != 0) { - //println("dataN: $dataN : trailingZeros=${dataN.trailingZeros()}") - return (16 * n) + (dataN.leadingZeros() - 16) - } - } - return maxBits - } - - /** Number of trailingZeros with the size of [maxBits] */ - fun trailingZeros(): Int { - if (isZero) return maxBits - for (n in 0 until data.size) { - val dataN = data[n] - if (dataN != 0) { - return 16 * n + dataN.trailingZeros() - } - } - return maxBits - } - - override operator fun plus(other: BigInt): CommonBigInt { - other as CommonBigInt - val l = this - val r = other - return when { - l.isZero -> r - r.isZero -> l - l.isNegative && r.isPositive -> r - l.absoluteValue - l.isPositive && r.isNegative -> l - r.absoluteValue - l.isNegative && r.isNegative -> -(l.absoluteValue + r.absoluteValue) - else -> CommonBigInt(UnsignedBigInt.add(this.data, other.data), signum) - } - } - - override operator fun minus(other: BigInt): CommonBigInt { - other as CommonBigInt - val l = this - val r = other - return when { - r.isZero -> l - l.isZero -> -r - l.isNegative && r.isNegative -> r.abs() - l.abs() // (-l) - (-r) == (-l) + (r) == (r - l) - l.isNegative && r.isPositive -> -(l.absoluteValue + r) // -l - r == -(l + r) - l.isPositive && r.isNegative -> l + r.absoluteValue // l - (-r) == l + r - l.isPositive && r.isPositive && l < r -> -(r - l) - else -> CommonBigInt(UnsignedBigInt.sub(l.data, r.data), 1) - } - } - - @OptIn(ExperimentalTime::class) - override infix fun pow(exponent: BigInt): CommonBigInt { - exponent as CommonBigInt - if (exponent.isNegative) throw BigIntNegativeExponentException() - if (exponent.isZero) return ONE - if (exponent == ONE) return this - var base = this - var expBit = 0 - val expMaxBits = exponent.significantBits - //println("$exponent -> maxBits=${exponent.maxBits}, leadingZeros=${exponent.leadingZeros()}, trailingZeros=${exponent.trailingZeros()}, expMaxBits=$expMaxBits") - if (expMaxBits < 32) return pow(exponent.toInt()) - var result = ONE - while (expBit < expMaxBits) { - if (exponent.getBit(expBit)) result *= base - base *= base - expBit++ - } - return result - } - - override infix fun pow(exponent: Int): CommonBigInt = powWithStats(exponent, null) - - private fun getLower(len: Int): CommonBigInt = - if (len >= data.size) this.absoluteValue else CommonBigInt(data.copyOfRange(0, len), 1) - private fun getUpper(len: Int): CommonBigInt = - if (len >= data.size) ZERO else CommonBigInt(data.copyOfRange(len, data.size), 1) - - override fun square(): CommonBigInt { - if (this.isZero) return ZERO - //return CommonBigInt(UnsignedBigInt.squareToLen(this.data), +1) - return when { - // Karatsuba - this.data.size > 128 -> { - val half: Int = (data.size + 1) / 2 - val l = getLower(half) ; val ul = l.square() - val u = getUpper(half) ; val us = u.square() - (((us shl (half * CHUNK_BITS)) + ((l + u).square() - (us + ul))) shl (half * CHUNK_BITS)) + ul - } - // Standard - else -> { - // @TODO: Optimize. Useful for .pow - this * this - } - } - } - - fun powWithStats(exponent: Int, stats: OpStats?): CommonBigInt { - //return this pow exponent.bi - if (exponent < 0) throw BigIntNegativeExponentException() - if (exponent == 0) return ONE - if (exponent == 1) return this - if (isZero) return if (exponent == 0) ONE else this - var iterCount = 0 - var multCount = 0 - var squareCount = 0 - stats?.set() - - var exp = exponent - var part = this.abs() - val pot: Int = part.trailingZeros() - var shift = pot * exp - if (pot > 0) part = part shr pot else shift = 0 - val remainingBits = part.countBits() - if (remainingBits == 1) return if (isNegative && exp and 1 == 1) MINUS_ONE shl shift else ONE shl shift - var result = ONE - while (exp != 0) { - if ((exp and 1) == 1) { - result *= part - multCount++ - } - exp = exp ushr 1 - if (exp != 0) { - part = part.square() - squareCount++ - } - iterCount++ - } - if (pot > 0) result = result shl shift - - stats?.set(iterations = iterCount, bigMultiplications = multCount, square = squareCount) - - return when { - signum < 0 && (exp and 1) == 1 -> -result - else -> result - } - } - - - data class OpStats(var iterations: Int = 0, var bigMultiplications: Int = 0, var square: Int = 0) { - fun set(iterations: Int = 0, bigMultiplications: Int = 0, square: Int = 0) { - this.iterations = iterations - this.bigMultiplications = bigMultiplications - this.square = square - } - } - - fun mulWithStats(other: CommonBigInt, stats: OpStats?): CommonBigInt { - stats?.iterations = 0 - return when { - this.isZero || other.isZero -> ZERO - this == ONE -> other - other == ONE -> this - this == TWO -> other shl 1 - other == TWO -> this shl 1 - other.countBits() == 1 -> CommonBigInt( - (this shl other.trailingZeros()).data, - if (this.signum == other.signum) +1 else -1 - ) - else -> CommonBigInt( - UnsignedBigInt.mul(this.data, other.data, stats), - if (this.signum == other.signum) +1 else -1 - ) - } - } - - override operator fun times(other: BigInt): CommonBigInt { - other as CommonBigInt - return when { - this.isOne -> other - other.isOne -> this - this.isZero -> ZERO - other.isZero -> ZERO - else -> mulWithStats(other, null) - } - } - override operator fun div(other: BigInt): CommonBigInt = divRem(other as CommonBigInt).div - override operator fun rem(other: BigInt): CommonBigInt = divRem(other as CommonBigInt).rem - - fun withBit(bit: Int, set: Boolean = true): CommonBigInt { - // return if (set) this or (ONE shl bit) else this and (ONE shl bit).inv() - val bitShift = (bit % 16) - val bitMask = 1 shl bitShift - val wordPos = bit / 16 - val out = CommonBigInt(data.copyOf(max(data.size, wordPos + 1)), if (signum == 0) 1 else signum, dummy) - val outData = out.data - outData[wordPos] = if (set) outData[wordPos] or bitMask else outData[wordPos] and bitMask.inv() - return out - } - - // Assumes positive non-zero values this > 0 && other > 0 - data class DivRem(val div: CommonBigInt, val rem: CommonBigInt) - - fun divRem(other: CommonBigInt): DivRem { - return when { - this.isZero -> DivRem( - ZERO, - ZERO - ) - other.isZero -> throw BigIntDivisionByZeroException() - this.isNegative && other.isNegative -> this.absoluteValue.divRem(other.absoluteValue).let { - DivRem(it.div, -it.rem) - } - this.isNegative && other.isPositive -> this.absoluteValue.divRem(other.absoluteValue).let { - DivRem(-it.div, -it.rem) - } - this.isPositive && other.isNegative -> this.absoluteValue.divRem(other.absoluteValue).let { - DivRem(-it.div, it.rem) - } - other == ONE -> DivRem(this, ZERO) - other == TWO -> DivRem(this shr 1, CommonBigInt(this.getBitInt(0)) as CommonBigInt) - other <= SMALL -> UnsignedBigInt.divRemSmall(this.data, other.toInt()).let { - DivRem( - CommonBigInt(it.div, signum), - CommonBigInt(it.rem) as CommonBigInt - ) - } - other.countBits() == 1 -> { - val bits = other.trailingZeros() - DivRem(this shr bits, this and ((ONE shl bits) - ONE)) - } - else -> this.divRemBig(other) - } - } - - // Simple euclidean division - private fun divRemBig(other: CommonBigInt): DivRem { - if (this.isZero) return DivRem(ZERO, ZERO) - if (other.isZero) throw BigIntDivisionByZeroException() - if (this.isNegative || other.isNegative) throw BigIntException("Non positive numbers") - val lbits = this.significantBits - val rbits = other.significantBits - var rem = this - var divisor = other - var divisorShift = 0 - var res = ZERO - val initialShiftBits = lbits - rbits + 1 - divisorShift += initialShiftBits - divisor = divisor shl initialShiftBits - - while (divisorShift >= 0) { - if (divisor.isZero) throw BigIntDivisionByZeroException() - - if (divisor <= rem) { - res = res.withBit(divisorShift) - rem -= divisor - } - divisorShift-- - divisor = divisor shr 1 - } - - return DivRem(res, rem) - } - - fun getBitInt(n: Int): Int = ((data[n / 16] ushr (n % 16)) and 1) - fun getBit(n: Int): Boolean = getBitInt(n) != 0 - - override infix fun shl(count: Int): CommonBigInt { - if (count == 0) return this - if (count < 0) return this shr (-count) - val blockShift = count / 16 - val smallShift = count % 16 - val out = UInt16ArrayZeroPad(data.size + blockShift + 1) - var carry = 0 - val count_rcp = 16 - smallShift - for (n in 0 until data.size + 1) { - val v = data[n] - out[n + blockShift] = ((carry) or (v shl smallShift)) - carry = v ushr count_rcp - } - if (carry != 0) throw BigIntException("ERROR!") - return CommonBigInt(out, signum) - } - - override infix fun shr(count: Int): CommonBigInt { - //if (this.isNegative) return -(this.absoluteValue shr count) - 1 - if (count < 0) return this shl (-count) - val blockShift = count / 16 - val smallShift = count % 16 - val out = UInt16ArrayZeroPad(data.size - blockShift) - var carry = 0 - val count_rcp = 16 - smallShift - val LOW_MASK = (1 shl smallShift) - 1 - for (n in data.size - 1 downTo blockShift) { - val v = data[n] - out[n - blockShift] = ((carry shl count_rcp) or (v ushr smallShift)) - carry = v and LOW_MASK - } - return CommonBigInt(out, signum) - } - - override operator fun compareTo(that: BigInt): Int { - that as CommonBigInt - if (this.isNegative && that.isPositiveOrZero) return -1 - if (this.isPositiveOrZero && that.isNegative) return +1 - val resUnsigned = UnsignedBigInt.compare(this.data, that.data) - return if (this.isNegative && that.isNegative) -resUnsigned else resUnsigned - } - - override fun hashCode(): Int = this.data.contentHashCode() * this.signum - override fun equals(other: Any?): Boolean = (other is CommonBigInt) && this.signum == other.signum && this.data.contentEquals(other.data) - - val absoluteValue get() = abs() - override fun abs() = if (this.isZero) ZERO else if (this.isPositive) this else CommonBigInt(this.data, 1) - - override operator fun unaryPlus(): CommonBigInt = this - override operator fun unaryMinus(): CommonBigInt = CommonBigInt(this.data, -signum, false) - - fun mulAddSmall(mul: Int, add: Int): CommonBigInt { - if ((mul and 0xFFFF) == mul && (add and 0xFFFF) == add) { - val temp = UInt16ArrayZeroPad(data.data.copyOf(data.size + 1)) - UnsignedBigInt.inplaceSmallMulAdd(temp, mul, add) - return CommonBigInt(temp, if (temp.isAllZero) 0 else if (signum == 0) 1 else signum) - } - val out = this * CommonBigInt(mul) - return if (add == 0) out else out + CommonBigInt(add) - } - - override operator fun plus(other: Int): CommonBigInt = plus(CommonBigInt(other)) - override operator fun minus(other: Int): CommonBigInt = minus(CommonBigInt(other)) - override operator fun times(other: Int): CommonBigInt = mulAddSmall(other, 0) - override operator fun times(other: Long): CommonBigInt = times(CommonBigInt(other)) - override operator fun div(other: Int): CommonBigInt = div(CommonBigInt(other)) - override operator fun rem(other: Int): CommonBigInt = rem(CommonBigInt(other)) - - override infix fun and(other: BigInt): CommonBigInt = bitwise(other as CommonBigInt, Int::and) - override infix fun or(other: BigInt): CommonBigInt = bitwise(other as CommonBigInt, Int::or) - override infix fun xor(other: BigInt): CommonBigInt = bitwise(other as CommonBigInt, Int::xor) - - override fun inv(): CommonBigInt = -(this + 1) - - private inline fun bitwise(other: CommonBigInt, op: (a: Int, b: Int) -> Int): CommonBigInt { - return CommonBigInt( - UInt16ArrayZeroPad(max(this.data.size, other.data.size)).also { - for (n in 0 until it.size) it[n] = op(this.data[n], other.data[n]) - }, 1 - ) - } - - override fun toString() = toString(10) - - override fun toString(radix: Int): String { - // @TODO: Estimate digits - val sb = StringBuilder() - toString(sb, radix) - return sb.toString() - } - - fun toString(sb: StringBuilder, radix: Int) { - if (this.isZero) { - sb.append(0) - return - } - if (this.isNegative) { - sb.append('-') - } - when (radix) { - // @TODO: Generalize to power of two radix - 2 -> toUnsignedString2(sb) - 16 -> toUnsignedString16(sb) - else -> toUnsignedStringGeneric(sb, radix) - } - } - - private fun toUnsignedString2(sb: StringBuilder) { - val mb = maxBits - var started = false - for (n in 0 until mb) { - val bit = getBit(mb - n - 1) - if (!started && !bit) continue - sb.append(if (bit) '1' else '0') - started = true - } - } - - private fun toUnsignedString16(sb: StringBuilder) { - var started = false - for (n in 0 until data.size) { - val i = data.size - 1 - n - val value = data[i] - for (m in 0 until 4) { - val digit = (value ushr 12 - (4 * m)) and 0xF - if (digit == 0 && !started) continue - sb.append(digit(digit)) - started = true - } - } - } - - private fun toUnsignedStringGeneric(sb: StringBuilder, radix: Int) { - if (radix !in 2..26) throw BigIntInvalidFormatException("Invalid radix $radix!") - - // Divide and conquer - //if (this.data.size > 20) return - - val out = StringBuilder() - var num = this - - // Optimize with mutable data - while (num != ZERO) { - val result = UnsignedBigInt.divRemSmall(num.data, radix) - out.append(digit(result.rem)) - num = CommonBigInt(result.div, 1) - } - sb.append(out.reversed().toString()) - } - - override fun toInt(): Int { - if (significantBits > 31) throw BigIntOverflowException("Can't represent CommonBigInt($this) as integer: maxBits=$maxBits, significantBits=$significantBits, trailingZeros=${trailingZeros()}") - val magnitude = (this.data[0].toLong() or (this.data[1].toLong() shl 16)) * signum - return magnitude.toInt() - } - - fun toBigNum(): BigNum = BigNum(this, 0) -} - -class UInt16ArrayZeroPad internal constructor(val data: IntArray) { - val isAllZero: Boolean get() = data.all { it == 0 } - val size get() = data.size - - constructor(size: Int) : this(IntArray(max(1, size))) - - operator fun get(index: Int): Int { - if (index !in data.indices) return 0 - return data[index] - } - operator fun set(index: Int, value: Int) { - if (index !in data.indices) { - if (value != 0) error("Trying to set a value different to 0 to index $index in UInt16ArrayZeroPad") - return - } - data[index] = value and UINT16_MASK - } - - fun contentHashCode(): Int = data.contentHashCode() - fun contentEquals(other: UInt16ArrayZeroPad) = this.data.contentEquals(other.data) - fun copyOf(size: Int = this.size): UInt16ArrayZeroPad = UInt16ArrayZeroPad(data.copyOf(size)) - fun copyOfRange(fromIndex: Int = 0, toIndex: Int = this.size): UInt16ArrayZeroPad = UInt16ArrayZeroPad(data.copyOfRange(fromIndex, toIndex)) - - override fun toString(): String = "${data.toList()}" -} - -internal fun uint16ArrayZeroPadOf(vararg values: Int) = - UInt16ArrayZeroPad(values.size).apply { for (n in 0 until values.size) this[n] = values[n] } - -private fun digit(v: Int): Char { - if (v in 0..9) return '0' + v - if (v in 10..26) return 'a' + (v - 10) - throw BigIntInvalidFormatException("Invalid digit $v") -} - -internal fun digit(c: Char): Int { - return when (c) { - in '0'..'9' -> c - '0' - in 'a'..'z' -> c - 'a' + 10 - in 'A'..'Z' -> c - 'A' + 10 - else -> throw BigIntInvalidFormatException("Invalid digit '$c'") - } -} - -internal fun digit(c: Char, radix: Int): Int { - val d = digit(c) - if (d >= radix) throw BigIntInvalidFormatException("Character '$c' interpreted as $d not in the radix=$radix") - return d -} - -internal object UnsignedBigInt { - inline fun carriedOp(out: UInt16ArrayZeroPad, signedCarry: Boolean, op: (index: Int) -> Int) { - var carry = 0 - for (n in 0 until out.data.size) { - val product = op(n) + carry - val res = product and UINT16_MASK - out.data[n] = res - carry = if (signedCarry) product shr UINT16_SHIFT else product ushr UINT16_SHIFT - } - if (carry != 0) error("Overflow in carriedOp") - } - - fun inplaceSmallMulAdd(v: UInt16ArrayZeroPad, mul: Int, add: Int) { - if (mul != 1) carriedOp(v, signedCarry = false) { v[it] * mul } - if (add != 0) carriedOp(v, signedCarry = false) { if (it == 0) v[it] + add else v[it] + 0 } - } - - fun inplaceSmallMulAdd(v: UInt16ArrayZeroPad, vv: UInt16ArrayZeroPad, mul: Int) { - carriedOp(v, signedCarry = false) { v[it] + (vv[it] * mul) } - } - - fun add(l: UInt16ArrayZeroPad, r: UInt16ArrayZeroPad): UInt16ArrayZeroPad { - val out = UInt16ArrayZeroPad(max(l.size, r.size) + 1) - carriedOp(out, signedCarry = false) { l[it] + r[it] } - return out - } - - // l >= 0 && r >= 0 && l >= r - fun sub(l: UInt16ArrayZeroPad, r: UInt16ArrayZeroPad): UInt16ArrayZeroPad { - val out = UInt16ArrayZeroPad(max(l.size, r.size) + 1) - carriedOp(out, signedCarry = true) { l[it] - r[it] } - return out - } - - fun squareToLen(x: UInt16ArrayZeroPad, len: Int = x.size, zlen: Int = len * 2, z: UInt16ArrayZeroPad = UInt16ArrayZeroPad(zlen)): UInt16ArrayZeroPad { - // Store the squares, right shifted one bit (i.e., divided by 2) - var lastProductLowWord = 0 - run { - var j = 0 - var i = 0 - while (j < len) { - val piece = x[j] - val product = piece * piece - z[i++] = lastProductLowWord shl 15 or (product ushr 17) - z[i++] = (product ushr 1) - lastProductLowWord = product - j++ - } - } - // Add in off-diagonal sums - var offset = 1 - for (i in 0 until len) { - val t = x[i - 1] - mulAdd(z, x, offset, i - 1, t) - addOne(z, offset - 1, i, t) - offset += 2 - } - // Shift back up and set low bit - primitiveLeftShift(z, zlen, 1) - z[zlen - 1] = z[zlen - 1] or (x[len - 1] and 1) - return z - } - - fun addOne(a: UInt16ArrayZeroPad, offset: Int, mlen: Int, carry: Int): Int { - for (n in offset until offset + mlen) { - if (n == offset + mlen) { - a[n] - } - } - var offset = offset - var mlen = mlen - offset = a.size - 1 - mlen - offset - val t = (a[offset]) + (carry) - a[offset] = t - if (t ushr 16 == 0) return 0 - while (--mlen >= 0) { - if (--offset < 0) { // Carry out of number - return 1 - } else { - a[offset]++ - if (a[offset] != 0) return 0 - } - } - return 1 - } - - fun primitiveLeftShift(a: UInt16ArrayZeroPad, len: Int, n: Int) { - if (len == 0 || n == 0) return - val n2 = 16 - n - var i = 0 - var c = a[i] - val m = i + len - 1 - while (i < m) { - val b = c - c = a[i + 1] - a[i] = b shl n or (c ushr n2) - i++ - } - a[len - 1] = a[len - 1] shl n - } - - fun mulAdd(o: UInt16ArrayZeroPad, i: UInt16ArrayZeroPad, offset: Int, len: Int, k: Int): Int { - var carry: Int = 0 - for (j in 0 until len) { - val product = (i[j]) * k + (o[offset + j]) + carry - o[offset + j] = product - carry = product ushr 16 - } - return carry - } - - // l >= 0 && r >= 0 - // TODO optimize using the Karatsuba algorithm: - // TODO: - https://en.wikipedia.org/wiki/Multiplication_algorithm#Karatsuba_multiplication - fun mul(l: UInt16ArrayZeroPad, r: UInt16ArrayZeroPad, stats: CommonBigInt.OpStats?): UInt16ArrayZeroPad { - var its = 0 - val out = UInt16ArrayZeroPad(l.size + r.size + 1) - for (rn in 0 until r.size) { - var carry = 0 - for (ln in 0 until l.size + 1) { - val n = ln + rn - val res = out[n] + (l[ln] * r[rn]) + carry - out[n] = res - carry = res ushr 16 - its++ - } - if (carry != 0) throw BigIntOverflowException("carry expected to be zero at this point") - } - stats?.iterations = its - return out - } - - class DivRemSmall(val div: UInt16ArrayZeroPad, val rem: Int) - - fun divRemSmall(value: UInt16ArrayZeroPad, r: Int): DivRemSmall { - val length = value.size - var rem = 0 - val qq = UInt16ArrayZeroPad(value.size) - for (n in 0 until length) { - val i = length - 1 - n - val dd = (rem shl 16) + value[i] - val q = dd / r - rem = dd - q * r - qq[i] = q - } - return DivRemSmall(qq, rem) - } - - fun compare(l: UInt16ArrayZeroPad, r: UInt16ArrayZeroPad): Int { - for (n in max(l.size, r.size) - 1 downTo 0) { - val vl = l[n] - val vr = r[n] - if (vl < vr) return -1 - if (vl > vr) return +1 - } - return 0 - } -} - -internal const val UINT16_MASK = 0xFFFF -internal const val UINT16_SHIFT = 16 diff --git a/kbignum/src/commonMain/kotlin/korlibs/bignumber/internal/IntExt.kt b/kbignum/src/commonMain/kotlin/korlibs/bignumber/internal/IntExt.kt deleted file mode 100644 index c089efb9fa..0000000000 --- a/kbignum/src/commonMain/kotlin/korlibs/bignumber/internal/IntExt.kt +++ /dev/null @@ -1,13 +0,0 @@ -package korlibs.bignumber.internal - -import kotlin.math.* - -// https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel -@OptIn(ExperimentalStdlibApi::class) -internal fun Int.bitCount(): Int = countOneBits() - -@OptIn(ExperimentalStdlibApi::class) -internal fun Int.trailingZeros(): Int = countTrailingZeroBits() - -@OptIn(ExperimentalStdlibApi::class) -internal fun Int.leadingZeros(): Int = countLeadingZeroBits() diff --git a/kbignum/src/commonMain/kotlin/korlibs/bignumber/internal/progressionUtil.kt b/kbignum/src/commonMain/kotlin/korlibs/bignumber/internal/progressionUtil.kt deleted file mode 100644 index 95473cb695..0000000000 --- a/kbignum/src/commonMain/kotlin/korlibs/bignumber/internal/progressionUtil.kt +++ /dev/null @@ -1,27 +0,0 @@ -package korlibs.bignumber.internal - -import korlibs.bignumber.BigInt - -/** - * @see kotlin.internal.mod - */ -internal fun mod(a: BigInt, b: BigInt): BigInt { - val mod = a % b - return if (mod >= BigInt.ZERO) mod else mod + b -} - -/** - * @see kotlin.internal.differenceModulo - */ -internal fun differenceModulo(a: BigInt, b: BigInt, c: BigInt): BigInt { - return mod(mod(a, c) - mod(b, c), c) -} - -/** - * @see kotlin.internal.getProgressionLastElement - */ -internal fun getProgressionLastElement(start: BigInt, end: BigInt, step: BigInt): BigInt = when { - step > BigInt.ZERO -> if (start >= end) end else end - differenceModulo(end, start, step) - step < BigInt.ZERO -> if (start <= end) end else end + differenceModulo(start, end, -step) - else -> throw IllegalArgumentException("Step is zero.") -} diff --git a/kbignum/src/commonMain/kotlin/korlibs/bignumber/ranges/BigIntRange.kt b/kbignum/src/commonMain/kotlin/korlibs/bignumber/ranges/BigIntRange.kt deleted file mode 100644 index 8926ff32eb..0000000000 --- a/kbignum/src/commonMain/kotlin/korlibs/bignumber/ranges/BigIntRange.kt +++ /dev/null @@ -1,109 +0,0 @@ -package korlibs.bignumber.ranges - -import korlibs.bignumber.BigInt -import korlibs.bignumber.internal.getProgressionLastElement - -/** - * Represents an inclusive range between two [BigInt] between [start]..[endInclusive]. - * - * @see kotlin.ranges.IntRange - */ -class BigIntRange( - start: BigInt, - endInclusive: BigInt -) : BigIntProgression(start, endInclusive, BigInt.ONE), ClosedRange { - override val start: BigInt get() = first - override val endInclusive: BigInt get() = last - - @Suppress("ConvertTwoComparisonsToRangeCheck") - override fun contains(value: BigInt): Boolean = first <= value && value <= last - - /** - * Checks whether the range is empty. - * - * The range is empty if its start value is greater than the end value. - */ - override fun isEmpty(): Boolean = first > last - - override fun equals(other: Any?): Boolean = - other is BigIntRange && (isEmpty() && other.isEmpty() || - first == other.first && last == other.last) - - override fun hashCode(): Int = - if (isEmpty()) -1 else (31 * first.toInt() + last.toInt()) - - override fun toString(): String = "$first..$last" - - companion object { - /** An empty range of values of type BigInt. */ - val EMPTY: IntRange = IntRange(1, 0) - } -} - -/** - * Represents an inclusive progression between two [BigInt] in the range [start]..[endInclusive] with a specific [step] - * - * @see kotlin.ranges.IntProgression - */ -open class BigIntProgression internal constructor( - start: BigInt, - endInclusive: BigInt, - val step: BigInt -) : Iterable { - init { - if (step == BigInt.ZERO) throw IllegalArgumentException("Step must be non-zero.") - } - - val first: BigInt = start - val last: BigInt = getProgressionLastElement(start, endInclusive, step) - - open fun isEmpty(): Boolean = if (step > BigInt.ZERO) first > last else first < last - - override fun iterator(): Iterator = BigIntProgressionIterator(first, last, step) - - override fun equals(other: Any?): Boolean = - other is BigIntProgression && (isEmpty() && other.isEmpty() || - first == other.first && last == other.last && step == other.step) - - override fun hashCode(): Int = - if (isEmpty()) -1 else (31 * (31 * first.toInt() + last.toInt()) + step.toInt()) - - override fun toString(): String = - if (step > BigInt.ZERO) "$first..$last step $step" else "$first downTo $last step ${-step}" - - /** - * @see IntProgression.step - */ - infix fun step(step: BigInt): BigIntProgression { - return fromClosedRange(first, last, if (this.step > BigInt.ZERO) step else -step) - } - - companion object { - fun fromClosedRange(rangeStart: BigInt, rangeEnd: BigInt, step: BigInt): BigIntProgression = - BigIntProgression(rangeStart, rangeEnd, step) - } -} - - -/** - * @see kotlin.ranges.IntProgressionIterator - */ -class BigIntProgressionIterator(first: BigInt, last: BigInt, val step: BigInt) : Iterator { - private val finalElement: BigInt = last - private var hasNext: Boolean = if (step > BigInt.ZERO) first <= last else first >= last - private var next: BigInt = if (hasNext) first else finalElement - - override fun hasNext(): Boolean = hasNext - - override fun next(): BigInt { - val value = next - if (value == finalElement) { - if (!hasNext) throw NoSuchElementException() - hasNext = false - } - else { - next += step - } - return value - } -} diff --git a/kbignum/src/commonMain/kotlin/korlibs/bignumber/ranges/ClosedBigNumRange.kt b/kbignum/src/commonMain/kotlin/korlibs/bignumber/ranges/ClosedBigNumRange.kt deleted file mode 100644 index f748bf91a9..0000000000 --- a/kbignum/src/commonMain/kotlin/korlibs/bignumber/ranges/ClosedBigNumRange.kt +++ /dev/null @@ -1,34 +0,0 @@ -package korlibs.bignumber.ranges - -import korlibs.bignumber.* - -/** - * Represents an inclusive range between two [BigNum] between [start]..[endInclusive]. - * - * @see kotlin.ranges.ClosedFloatRange - */ -class ClosedBigNumRange( - override val start: BigNum, - override val endInclusive: BigNum -) : ClosedRange { - - @Suppress("ConvertTwoComparisonsToRangeCheck") - override fun contains(value: BigNum): Boolean = value >= start && value <= endInclusive - - /** - * @see kotlin.ranges.ClosedFloatRange.isEmpty - */ - @Suppress("SimplifyNegatedBinaryExpression") - override fun isEmpty(): Boolean = !(start <= endInclusive) - - override fun equals(other: Any?): Boolean { - return other is ClosedBigNumRange && (isEmpty() && other.isEmpty() || - start == other.start && endInclusive == other.endInclusive) - } - - override fun hashCode(): Int { - return if (isEmpty()) -1 else 31 * start.hashCode() + endInclusive.hashCode() - } - - override fun toString(): String = "$start..$endInclusive" -} diff --git a/kbignum/src/commonTest/kotlin/korlibs/bignumber/BigIntProgressionTest.kt b/kbignum/src/commonTest/kotlin/korlibs/bignumber/BigIntProgressionTest.kt deleted file mode 100644 index cfc4f72ae4..0000000000 --- a/kbignum/src/commonTest/kotlin/korlibs/bignumber/BigIntProgressionTest.kt +++ /dev/null @@ -1,32 +0,0 @@ -package korlibs.bignumber - -import korlibs.bignumber.ranges.* -import kotlin.test.* - -class BigIntProgressionTest { - @Test - fun test() { - val p1 = BigIntProgression(0.bi, 10.bi, 1.bi) - val p2 = BigIntProgression(0.bi, 10.bi, 1.bi) - val p3 = BigIntProgression(10.bi, 0.bi, (-1).bi) - assertEquals(p1.hashCode(), p2.hashCode()) - assertEquals(p1, p2) - assertNotEquals(p1, p3) - assertNotEquals(p1, Unit) - assertEquals("0..10 step 1", p1.toString()) - } - - @Test - fun testNext() { - run { - val iterator = BigIntProgressionIterator(0.bi, 0.bi, step = 1.bi) - iterator.next() - assertFailsWith { iterator.next() } - } - run { - val iterator = BigIntProgressionIterator(0.bi, 0.bi, step = (-1).bi) - iterator.next() - assertFailsWith { iterator.next() } - } - } -} diff --git a/kbignum/src/commonTest/kotlin/korlibs/bignumber/BigIntRangeTest.kt b/kbignum/src/commonTest/kotlin/korlibs/bignumber/BigIntRangeTest.kt deleted file mode 100644 index 58fe552989..0000000000 --- a/kbignum/src/commonTest/kotlin/korlibs/bignumber/BigIntRangeTest.kt +++ /dev/null @@ -1,35 +0,0 @@ -package korlibs.bignumber - -import korlibs.bignumber.ranges.* -import kotlin.test.* - -class BigIntRangeTest { - @Test - fun testContains() { - assertEquals("0..10", (0.bi .. 10.bi).toString()) - assertEquals(0.bi, (0.bi .. 10.bi).start) - assertEquals(10.bi, (0.bi .. 10.bi).endInclusive) - assertEquals((0.bi .. 10.bi), (0.bi .. 10.bi)) - assertEquals((0.bi .. 10.bi).hashCode(), (0.bi .. 10.bi).hashCode()) - assertTrue { 0.bi in (0.bi .. 10.bi) } - assertTrue { 5.bi in (0.bi .. 10.bi) } - assertTrue { 10.bi in (0.bi .. 10.bi) } - assertFalse { (-1).bi in (0.bi .. 10.bi) } - assertFalse { 11.bi in (0.bi .. 10.bi) } - } - - @Test - fun testIsEmpty() { - assertTrue { (1.bi .. 0.bi).isEmpty() } - assertTrue { BigIntRange.EMPTY.isEmpty() } - } - - @Test - fun testHashCodeEquals() { - assertEquals(BigIntRange(1.bi, 0.bi).hashCode(), BigIntRange(1.bi, 0.bi).hashCode()) - assertEquals(BigIntRange(1.bi, 0.bi), BigIntRange(1.bi, 0.bi)) - assertNotEquals(BigIntRange(1.bi, 0.bi), BigIntRange(0.bi, 0.bi)) - assertNotEquals(BigIntRange(1.bi, 0.bi), BigIntRange(1.bi, 1.bi)) - assertNotEquals(BigIntRange(1.bi, 0.bi), 1) - } -} diff --git a/kbignum/src/commonTest/kotlin/korlibs/bignumber/BigIntTest.kt b/kbignum/src/commonTest/kotlin/korlibs/bignumber/BigIntTest.kt deleted file mode 100644 index 2e58946017..0000000000 --- a/kbignum/src/commonTest/kotlin/korlibs/bignumber/BigIntTest.kt +++ /dev/null @@ -1,361 +0,0 @@ -package korlibs.bignumber - -import korlibs.bignumber.internal.* -import kotlin.test.* - -abstract class AbstractBigIntTest { - @Test - fun testInvalidRadix() { - "1f".bi(16) - assertFailsWith { "1f".bi(10) } - } - - @Test - fun testLong() { - assertEquals(1L.bi, 1L.bi) - } - - @Test - fun testDivisionByZero() { - assertFailsWith { 1.bi / 0.bi } - } - - @Test - fun testNegativeExponent() { - assertFailsWith { 1.bi.pow(-1) } - } - - @Test - fun testMultiplyPowerOfTwo() { - assertEquals("1", (1.bi * 1.bi).toString(2)) - assertEquals("10", (1.bi * 2.bi).toString(2)) - assertEquals("100", (1.bi * 4.bi).toString(2)) - assertEquals("1000", (1.bi * 8.bi).toString(2)) - assertEquals("1000000000000000", (1.bi * (1 shl 15)).toString(2)) - assertEquals("10000000000000000", (1.bi * (1 shl 16)).toString(2)) - assertEquals("100000000000000000", (1.bi * (1 shl 17)).toString(2)) - assertEquals( - "100000000000000000000000000000000000000000000000000000000000000", - (1.bi * (1L shl 62)).toString(2) - ) - assertEquals("1${"0".repeat(128)}", (1.bi * (1.bi shl 128)).toString(2)) - } - - @Test - fun testAddSmall() { - assertEquals("10", (1.bi + 1.bi).toString(2)) - assertEquals("11", (1.bi + 1.bi + 1.bi).toString(2)) - assertEquals(108888887.bi, 99999999.bi + 8888888.bi) - assertEquals("108888887", (99999999.bi + 8888888.bi).toString()) - } - - @Test - fun testSub() { - assertEquals("25", "${100.bi - 75.bi}") - assertEquals("-25", "${75.bi - 100.bi}") - assertEquals("0", "${100.bi - 100.bi}") - assertEquals("0", "${(-100).bi - (-100).bi}") - assertEquals("-50", "${(-100).bi - (-50).bi}") - assertEquals("-150", "${(-100).bi - (50).bi}") - assertEquals("150", "${(100).bi - (-50).bi}") - } - - @Test - fun testSubInt() { - val res = (-9999999).bi - (-8888888).bi - //println("$res") - - val items = listOf(-9999999, -8888888, -100, -50, 0, +50, +100, +8888888, +9999999) - for (l in items) for (r in items) { - //println("$l - $r = ${l - r}") - //println("${l.n} - ${r.n} = ${(l - r).n}") - //println("${l.n} - ${r.n} = ${(l.n - r.n)}") - assertEquals((l - r).bi, l.bi - r.bi) - } - } - - @Test - fun testToString2() { - assertEquals("0", "0".bi(2).toString(2)) - assertEquals("101011", "101011".bi(2).toString(2)) - assertEquals("1000000010000001", "1000000010000001".bi(2).toString(2)) - assertEquals("1000000000000000", "1000000000000000".bi(2).toString(2)) - } - - @Test - fun testParseRadix() { - assertEquals("1", "1".bi(2).toString(2)) - assertEquals("-1", "-1".bi(2).toString(2)) - assertEquals("1", "1".bi(8).toString(8)) - assertEquals("-1", "-1".bi(8).toString(8)) - assertEquals("f7", "f7".bi(16).toString(16)) - assertEquals("-f7", "-f7".bi(16).toString(16)) - } - - @Test - fun testToString10() { - assertEquals("0", "${0.bi}") - assertEquals("1", "${1.bi}") - assertEquals("10", "${10.bi}") - assertEquals("100", "${100.bi}") - assertEquals("999", "${999.bi}") - } - - @Test - fun testCompare() { - assertTrue(1.bi == 1.bi) - assertTrue(0.bi < 1.bi) - assertTrue(1.bi > 0.bi) - assertTrue(0.bi >= 0.bi) - assertTrue(1.bi >= 0.bi) - assertTrue(0.bi <= 0.bi) - assertTrue(0.bi <= 1.bi) - - assertTrue((-1).bi < 1.bi) - assertTrue((1).bi > (-1).bi) - - assertTrue((-2).bi < (-1).bi) - } - - @Test - fun testBitwise() { - assertEquals("${0b101 xor 0b110}", "${0b101.bi xor 0b110.bi}") - assertEquals("${0b101 and 0b110}", "${0b101.bi and 0b110.bi}") - assertEquals("${0b101 or 0b110}", "${0b101.bi or 0b110.bi}") - } - - @Test - fun testTrailingZeros() { - assertEquals(32, 0.trailingZeros()) - assertEquals(0, 1.trailingZeros()) - assertEquals(1, 2.trailingZeros()) - assertEquals(16, CommonBigInt("000000000000000000000000000000", 2).trailingZeros()) - assertEquals(0, CommonBigInt("000000000000000000000000000001", 2).trailingZeros()) - assertEquals(7, CommonBigInt("100000000000000000000010000000", 2).trailingZeros()) - assertEquals(5, CommonBigInt("100000000000000000000010100000", 2).trailingZeros()) - assertEquals(29, CommonBigInt("100000000000000000000000000000", 2).trailingZeros()) - assertEquals(30, CommonBigInt("1000000000000000000000000000000", 2).trailingZeros()) - assertEquals(31, CommonBigInt("10000000000000000000000000000000", 2).trailingZeros()) - assertEquals(32, CommonBigInt("100000000000000000000000000000000", 2).trailingZeros()) - assertEquals(33, CommonBigInt("1000000000000000000000000000000000", 2).trailingZeros()) - assertEquals(40, CommonBigInt("10000000000000000000000000000000000000000", 2).trailingZeros()) - } - - @Test - fun testLeadingZeros() { - assertEquals(32, 0.leadingZeros()) - assertEquals(31, 1.leadingZeros()) - assertEquals(30, 2.leadingZeros()) - assertEquals(15, CommonBigInt("000000000000000000000000000001", 2).leadingZeros()) - assertEquals(2, CommonBigInt("100000000000000000000010000000", 2).leadingZeros()) - assertEquals(2, CommonBigInt("100000000000000000000010100000", 2).leadingZeros()) - assertEquals(2, CommonBigInt("100000000000000000000000000000", 2).leadingZeros()) - assertEquals(1, CommonBigInt("1000000000000000000000000000000", 2).leadingZeros()) - assertEquals(0, CommonBigInt("10000000000000000000000000000000", 2).leadingZeros()) - assertEquals(15, CommonBigInt("100000000000000000000000000000000", 2).leadingZeros()) - assertEquals(14, CommonBigInt("1000000000000000000000000000000000", 2).leadingZeros()) - assertEquals(7, CommonBigInt("10000000000000000000000000000000000000000", 2).leadingZeros()) - } - - @Test - fun testBitCount() { - assertEquals(0, CommonBigInt("00000000000000000000000000000000000000000", 2).countBits()) - assertEquals(1, CommonBigInt("00000000000000000000000000000000000000001", 2).countBits()) - assertEquals(1, CommonBigInt("10000000000000000000000000000000000000000", 2).countBits()) - assertEquals(2, CommonBigInt("10000000000000000000000000000000000000001", 2).countBits()) - assertEquals(7, CommonBigInt("10000000001000001000000010000100001000001", 2).countBits()) - } - - @Test - fun testSignificantBits() { - assertEquals(0, CommonBigInt(0).significantBits) - assertEquals(1, CommonBigInt(1).significantBits) - assertEquals(2, CommonBigInt(2).significantBits) - assertEquals(2, CommonBigInt(3).significantBits) - assertEquals(16, CommonBigInt(0xFFFF).significantBits) - assertEquals(24, CommonBigInt(0xFFFFFF).significantBits) - assertEquals(32, CommonBigInt(0xFFFFFFFFL).significantBits) - assertEquals(40, CommonBigInt(0xFFFFFFFFFFL).significantBits) - assertEquals(48, CommonBigInt(0xFFFFFFFFFFFFL).significantBits) - } - - @Test - fun testRadixPrefix() { - assertEquals("FF".toInt(16), "0xFF".bi.toInt()) - assertEquals("777".toInt(8), "0o777".bi.toInt()) - assertEquals("111".toInt(2), "0b111".bi.toInt()) - assertEquals("-FF".toInt(16), "-0xFF".bi.toInt()) - assertEquals("-777".toInt(8), "-0o777".bi.toInt()) - assertEquals("-111".toInt(2), "-0b111".bi.toInt()) - } - - @Test - fun testInvalid() { - assertFailsWith { "2".bi(2) } - assertFailsWith { "-2".bi(2) } - assertFailsWith { "a".bi(10) } - assertFailsWith { "-a".bi(10) } - assertFailsWith { "0xg".bi } - assertFailsWith { "0o8".bi } - assertFailsWith { "0b2".bi } - assertFailsWith { "-0b2".bi } - } - - @Test - fun testLongDiv() { - //assertEquals("500000000".bi, "1000000000000000000".bi / "2000000000".bi) - assertEquals("5000000000".bi, "100000000000000000000".bi / "20000000000".bi) - assertEquals("-5000000000".bi, "-100000000000000000000".bi / "20000000000".bi) - assertEquals("-5000000000".bi, "100000000000000000000".bi / "-20000000000".bi) - assertEquals("5000000000".bi, "-100000000000000000000".bi / "-20000000000".bi) - } - - @Test - open fun testInv() { - assertEquals( - listOf((-65536).bi, (-1).bi, (-4661).bi), - listOf("0xFFFF".bi.inv(), "0x0000".bi.inv(), "0x1234".bi.inv()) - ) - } - - @Test - fun testMultComplexity() { - val num1 = CommonBigInt("1".repeat(1024)) - val stats = CommonBigInt.OpStats() - val res = num1.mulWithStats(num1, stats) - assertEquals(2047, res.toString().length) - //assertEquals(1024, stats.iterations) - } - - @Test - fun testOtherToString2() { - assertEquals("11000000111001", 12345.bi.toString(2)) - assertEquals("3000321", 12345.bi.toString(4)) - assertEquals("12345", 12345.bi.toString(10)) - assertEquals("3039", 12345.bi.toString(16)) - - //assertEquals(1024, stats.iterations) - } - - @Test - fun testMixed() { - val int1 = "9191291821821972198723892731927412419757607241902412742141904810123913021931".bi - val int2 = "121231246717581291824912849128509185124190310741841824712837131738172".bi - assertEquals( - """ - 9191291943053218916305184556840261548266792366092723483983729522961044760103 - 9191291700590725481142600907014563291248422117712102000300080097286781283759 - 1114271766504586738871424632299032567834176034059871342978560190227960452332298253865995506036055166329263498074211029232849112689623243185850132 - 75816194 - 101819965766955686129307629109600080549778649042399450539859107464563 - """.trimIndent(), - """ - ${int1 + int2} - ${int1 - int2} - ${int1 * int2} - ${int1 / int2} - ${int1 % int2} - """.trimIndent() - ) - } - - @Test - fun testUsesNativeImplementationDoNotThrow() { - BigInt.usesNativeImplementation - } - - @Test - fun testRegressionIssue14() { - assertEquals(BigInt("7020682204035638644"), BigInt("616e794474736574", 16)) - - assertEquals(BigInt("15"), BigInt("f", 16)) - assertEquals(BigInt("255"), BigInt("ff", 16)) - assertEquals(BigInt("4095"), BigInt("fff", 16)) - assertEquals(BigInt("65535"), BigInt("ffff", 16)) - assertEquals(BigInt("1048575"), BigInt("fffff", 16)) - assertEquals(BigInt("16777215"), BigInt("ffffff", 16)) - assertEquals(BigInt("268435455"), BigInt("fffffff", 16)) - assertEquals(BigInt("4294967295"), BigInt("ffffffff", 16)) - assertEquals(BigInt("68719476735"), BigInt("fffffffff", 16)) - assertEquals(BigInt("1099511627775"), BigInt("ffffffffff", 16)) - assertEquals(BigInt("17592186044415"), BigInt("fffffffffff", 16)) - assertEquals(BigInt("281474976710655"), BigInt("ffffffffffff", 16)) - assertEquals(BigInt("4503599627370495"), BigInt("fffffffffffff", 16)) - assertEquals(BigInt("72057594037927935"), BigInt("ffffffffffffff", 16)) - assertEquals(BigInt("1152921504606846975"), BigInt("fffffffffffffff", 16)) - assertEquals(BigInt("18446744073709551615"), BigInt("ffffffffffffffff", 16)) - assertEquals(BigInt("295147905179352825855"), BigInt("fffffffffffffffff", 16)) - assertEquals(BigInt("4722366482869645213695"), BigInt("ffffffffffffffffff", 16)) - assertEquals(BigInt("75557863725914323419135"), BigInt("fffffffffffffffffff", 16)) - assertEquals(BigInt("1208925819614629174706175"), BigInt("ffffffffffffffffffff", 16)) - assertEquals(BigInt("19342813113834066795298815"), BigInt("fffffffffffffffffffff", 16)) - assertEquals(BigInt("309485009821345068724781055"), BigInt("ffffffffffffffffffffff", 16)) - assertEquals(BigInt("4951760157141521099596496895"), BigInt("fffffffffffffffffffffff", 16)) - assertEquals(BigInt("79228162514264337593543950335"), BigInt("ffffffffffffffffffffffff", 16)) - assertEquals(BigInt("1267650600228229401496703205375"), BigInt("fffffffffffffffffffffffff", 16)) - assertEquals(BigInt("20282409603651670423947251286015"), BigInt("ffffffffffffffffffffffffff", 16)) - assertEquals(BigInt("324518553658426726783156020576255"), BigInt("fffffffffffffffffffffffffff", 16)) - assertEquals(BigInt("5192296858534827628530496329220095"), BigInt("ffffffffffffffffffffffffffff", 16)) - assertEquals(BigInt("83076749736557242056487941267521535"), BigInt("fffffffffffffffffffffffffffff", 16)) - assertEquals(BigInt("1329227995784915872903807060280344575"), BigInt("ffffffffffffffffffffffffffffff", 16)) - } - - @Test - fun testIssue13() { - assertFailsWith { BigInt("") } - } - - @Test - fun testHashCode() { - assertEquals(BigInt("0").hashCode(), BigInt("0").hashCode()) - assertEquals(BigInt("123").hashCode(), BigInt("123").hashCode()) - } - - // Big Integer - abstract val Long.bi: BigInt - abstract val Int.bi: BigInt - abstract val String.bi: BigInt - abstract fun String.bi(radix: Int): BigInt -} - -class BigIntTestCommon : AbstractBigIntTest() { - override val Long.bi: BigInt get() = CommonBigInt(this) - override val Int.bi: BigInt get() = CommonBigInt(this) - override val String.bi: BigInt get() = CommonBigInt(this) - override fun String.bi(radix: Int): BigInt = CommonBigInt(this, radix) - - @Test - fun testEmpty() {} - - @Test - fun testBigIntCompanion() { - assertEquals(1.bi, CommonBigInt.invoke(1)) - assertEquals(1.bi, CommonBigInt.invoke(1L)) - assertEquals(1.bi, CommonBigInt.invoke("1")) - assertEquals(1.bi, CommonBigInt.invoke("1", 16)) - } - - @Test - fun testBigIntSmall() { - assertTrue { CommonBigInt(10).isSmall } - assertTrue { CommonBigInt.TEN.isSmall } - assertTrue { CommonBigInt.SMALL.isSmall } - assertFalse { CommonBigInt(100000).isSmall } - } -} - -class BigIntTestPlatform : AbstractBigIntTest() { - override val Long.bi: BigInt get() = BigInt(this) - override val Int.bi: BigInt get() = BigInt(this) - override val String.bi: BigInt get() = BigInt(this) - override fun String.bi(radix: Int): BigInt = BigInt(this, radix) - - //@Test - //@Ignore // Disabled because in the JVM BigInteger.inv() works differently than in common - //override fun testInv() { - // super.testInv() - //} - - @Test - fun testEmpty() {} -} diff --git a/kbignum/src/commonTest/kotlin/korlibs/bignumber/BigNumTest.kt b/kbignum/src/commonTest/kotlin/korlibs/bignumber/BigNumTest.kt deleted file mode 100644 index 34516a73ff..0000000000 --- a/kbignum/src/commonTest/kotlin/korlibs/bignumber/BigNumTest.kt +++ /dev/null @@ -1,189 +0,0 @@ -package korlibs.bignumber - -import kotlin.test.* - -class BigNumTest { - @Test - fun testBigNum() { - assertEquals(1.bi, 1L.bi) - assertEquals("1".bi, "1".bi) - assertEquals("1".bi, "1".bi(16)) - assertEquals(1.bn, 1L.bn) - assertEquals("1".bn, "1".bn) - } - - @Test - fun testToString() { - assertEquals("0.019", BigNum(19.bi, 3).toString()) - assertEquals("0.19", BigNum(19.bi, 2).toString()) - assertEquals("1.9", BigNum(19.bi, 1).toString()) - assertEquals("19", BigNum(19.bi, 0).toString()) - } - - @Test - fun testToStringE() { - assertEquals("0.1", "1e-1".bn.toString()) - assertEquals("0.01", "1e-2".bn.toString()) - assertEquals("0.0001", "1e-4".bn.toString()) - assertEquals("1", "1e0".bn.toString()) - assertEquals("0.01", "0.1e-1".bn.toString()) - assertEquals("0.001", "0.1e-2".bn.toString()) - assertEquals("0.00001", "0.1e-4".bn.toString()) - assertEquals("0.1", "0.1e0".bn.toString()) - } - - @Test - fun testToStringE2() { - assertEquals("10", "1e+1".bn.toString()) - assertEquals("100", "1e+2".bn.toString()) - assertEquals("1000", "1e+3".bn.toString()) - assertEquals("10000", "1e+4".bn.toString()) - assertEquals("100000", "10e+4".bn.toString()) - } - - @Test - fun testAddSameScale() { - assertEquals("0.050", (BigNum(20.bi, 3) + BigNum(30.bi, 3)).toString()) - } - - @Test - fun testPow() { - assertEquals("1", "${10.bi pow 0}") - assertEquals("10", "${10.bi pow 1}") - assertEquals("10000000000", "${10.bi pow 10}") - assertEquals( - "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "${10.bi pow 100}" - ) - - assertEquals("1", "${10.bi pow 0.bi}") - assertEquals("10", "${10.bi pow 1.bi}") - assertEquals("10000000000", "${10.bi pow 10.bi}") - assertEquals( - "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "${10.bi pow 100.bi}" - ) - } - - @Test - fun testAddDifferentScale() { - assertEquals("11.51", (BigNum("1.2") + BigNum("10.31")).toString()) - } - - @Test - fun testMultiply() { - assertEquals("2.4".bn, "1.2".bn * "2".bn) - assertEquals("0.12".bn, "1.2".bn * "0.1".bn) - assertEquals("0.012".bn, "1.2".bn * "0.01".bn) - assertEquals("0.012".bn, "0.01".bn * "1.2".bn) - } - - @Test - fun testDivide() { - //val rr = BigDecimal("1.000") - assertEquals("0.333".bn, "1.000".bn / "3".bn) - assertEquals("0.333".bn, "1.000".bn / "3.000".bn) - assertEquals("0.3".bn, "1.0".bn / "3".bn) - assertEquals("0".bn, "1".bn / "3".bn) - assertEquals("0".bn, "1".bn / "3.000".bn) - } - - @Test - fun testFromString() { - //assertEquals("-50", BigNum("-050").toString()) - assertEquals("50", BigNum("050").toString()) - assertEquals("0.00005000000", BigNum("0.00005000000").toString()) - assertEquals("0.050", BigNum("0.050").toString()) - assertEquals("0.050", BigNum(".050").toString()) - } - - @Test - fun testCompare() { - assertTrue("1.5".bn < "3.0".bn) - assertTrue("1.5".bn <= "1.5".bn) - } - - @Test - fun testNegative() { - assertEquals("-0.0001", "-0.0001".bn.toString()) - } - - @Test - fun testConvertToScale() { - assertEquals(3, "0.001".bn.scale) - assertEquals(4, "0.001".bn.convertToScale(4).scale) - assertEquals("0.001", "0.001".bn.convertToScale(3).toString()) - assertEquals("0.0010", "0.001".bn.convertToScale(4).toString()) - assertEquals("0.001", "0.001".bn.convertToScale(4).convertToScale(3).toString()) - //"0.001".bn.convertToScale() - //assertEquals("-0.0001", "-0.0001".bn.toString()) - } - - @Test - fun testConvert() { - assertEquals(1.bi, "1.2".bn.toBigInt()) - assertEquals(1.bi, "1.9".bn.toBigInt()) - } - - @Test - fun testConvertCeil() { - assertEquals(1.bi, "1.0".bn.toBigIntCeil()) - assertEquals(2.bi, "1.1".bn.toBigIntCeil()) - assertEquals(2.bi, "1.9123".bn.toBigIntCeil()) - } - - @Test - fun testConvertFloor() { - assertEquals(1.bi, "1.0".bn.toBigIntFloor()) - assertEquals(1.bi, "1.1".bn.toBigIntFloor()) - assertEquals(1.bi, "1.9123".bn.toBigIntFloor()) - } - - @Test - fun testConvertRound() { - assertEquals(1.bi, "1.0".bn.toBigIntRound()) - assertEquals(1.bi, "1.4".bn.toBigIntRound()) - assertEquals(1.bi, "1.49".bn.toBigIntRound()) - assertEquals(1.bi, "1.4123456".bn.toBigIntRound()) - assertEquals(1.bi, "1.499999".bn.toBigIntRound()) - assertEquals(2.bi, "1.5".bn.toBigIntRound()) - assertEquals(2.bi, "1.500".bn.toBigIntRound()) - assertEquals(2.bi, "1.51".bn.toBigIntRound()) - assertEquals(2.bi, "1.512345".bn.toBigIntRound()) - assertEquals(2.bi, "1.6".bn.toBigIntRound()) - assertEquals(2.bi, "1.9123".bn.toBigIntRound()) - } - - @Test - fun testDecimalPart() { - assertEquals(9123.bi, "1.9123".bn.decimalPart) - assertEquals(0.bi, "1.0".bn.decimalPart) - } - - @Test - fun testDiv() { - val bi1 = BigNum("1.000000000") - val bi2 = BigNum("2.000000000") - assertEquals( - expected = 0.5.bn, - actual = bi1 / bi2 - ) - } - - @Test - fun testDiv2() { - val bi1 = BigNum("1.000000000000000000000000000000000000000") - val bi2 = BigNum("2.000000000000000000000000000000000000000") - assertEquals( - expected = 0.5.bn, - actual = bi1 / bi2 - ) - } - - @Test - fun testHashCode() { - assertEquals(BigNum("0.123").hashCode(), BigNum("0.123").hashCode()) - assertEquals(BigNum("123.123").hashCode(), BigNum("123.123").hashCode()) - } - -} diff --git a/kbignum/src/commonTest/kotlin/korlibs/bignumber/RangesTest.kt b/kbignum/src/commonTest/kotlin/korlibs/bignumber/RangesTest.kt deleted file mode 100644 index 71e3345691..0000000000 --- a/kbignum/src/commonTest/kotlin/korlibs/bignumber/RangesTest.kt +++ /dev/null @@ -1,19 +0,0 @@ -package korlibs.bignumber - -import kotlin.test.* - -class RangesTest { - @Test - fun progressionTest() { - assertEquals((1.bi..4.bi).toList().size, 4) - assertEquals((1.bi..4.bi step 2.bi).toList().size, 2) - assertEquals((1.bi..4.bi step 5.bi).toList().size, 1) - } - - @Test - fun containsTest() { - assertTrue(BigInt.ZERO in BigInt("-99999999999999999999999999999999999999999999999")..BigInt("99999999999999999999999999999999999999999999999")) - assertTrue(BigNum.ZERO in BigNum("-99999999999999999999999999999999999999999999999")..BigNum("99999999999999999999999999999999999999999999999")) - assertTrue(BigNum.ZERO in BigNum("-0.000000000000000000000000000000000000000000001")..BigNum("0.000000000000000000000000000000000000000000001")) - } -} diff --git a/kbignum/src/commonTest/kotlin/korlibs/bignumber/internal/IntExtTest.kt b/kbignum/src/commonTest/kotlin/korlibs/bignumber/internal/IntExtTest.kt deleted file mode 100644 index e096b7881c..0000000000 --- a/kbignum/src/commonTest/kotlin/korlibs/bignumber/internal/IntExtTest.kt +++ /dev/null @@ -1,41 +0,0 @@ -package korlibs.bignumber.internal - -import kotlin.test.Test -import kotlin.test.assertEquals - -class IntExtTest { - @Test - fun testBitCount() { - assertEquals(0, 0b0.bitCount()) - assertEquals(1, 0b1.bitCount()) - assertEquals(1, 0b10.bitCount()) - assertEquals(2, 0b11.bitCount()) - assertEquals(3, 0b111.bitCount()) - assertEquals(3, 0b10101.bitCount()) - assertEquals(3, 0b101010000.bitCount()) - } - - @Test - fun testTrailingZeros() { - assertEquals(32, 0b0.trailingZeros()) - assertEquals(0, (-1).trailingZeros()) - assertEquals(0, 0b1.trailingZeros()) - assertEquals(1, 0b10.trailingZeros()) - assertEquals(0, 0b11.trailingZeros()) - assertEquals(0, 0b111.trailingZeros()) - assertEquals(0, 0b10101.trailingZeros()) - assertEquals(4, 0b101010000.trailingZeros()) - } - - @Test - fun testLeadingZeros() { - assertEquals(32, 0b0.leadingZeros()) - assertEquals(0, (-1).leadingZeros()) - assertEquals(31, 0b1.leadingZeros()) - assertEquals(30, 0b10.leadingZeros()) - assertEquals(30, 0b11.leadingZeros()) - assertEquals(29, 0b111.leadingZeros()) - assertEquals(27, 0b10101.leadingZeros()) - assertEquals(23, 0b0101010000.leadingZeros()) - } -} diff --git a/kbignum/src/commonTest/kotlin/korlibs/bignumber/internal/ProgressionUtilTest.kt b/kbignum/src/commonTest/kotlin/korlibs/bignumber/internal/ProgressionUtilTest.kt deleted file mode 100644 index 9e4ad77cc4..0000000000 --- a/kbignum/src/commonTest/kotlin/korlibs/bignumber/internal/ProgressionUtilTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package korlibs.bignumber.internal - -import korlibs.bignumber.* -import kotlin.test.* - -class ProgressionUtilTest { - @Test - fun test() { - assertEquals(4.bi, getProgressionLastElement(0.bi, 4.bi, (+1).bi)) - assertEquals(0.bi, getProgressionLastElement((4).bi, 0.bi, (-1).bi)) - - assertEquals((-1).bi, getProgressionLastElement((-4).bi, 0.bi, (+3).bi)) - assertEquals(3.bi, getProgressionLastElement(0.bi, 4.bi, (+3).bi)) - assertEquals((1).bi, getProgressionLastElement((4).bi, 0.bi, (-3).bi)) - assertFailsWith { getProgressionLastElement(0.bi, 4.bi, 0.bi) } - } -} diff --git a/kbignum/src/jsMain/kotlin/korlibs/bignumber/BigIntJs.kt b/kbignum/src/jsMain/kotlin/korlibs/bignumber/BigIntJs.kt deleted file mode 100644 index 2da660418b..0000000000 --- a/kbignum/src/jsMain/kotlin/korlibs/bignumber/BigIntJs.kt +++ /dev/null @@ -1,83 +0,0 @@ -package korlibs.bignumber - -import korlibs.bignumber.ext.* - -actual val BigIntNativeFactory: BigIntConstructor = object : BigIntConstructor { - override fun create(value: Int): BigInt = - if (supportNativeJsBigInt) JsBigInt.create(value) else CommonBigInt.create(value) - - override fun create(value: String, radix: Int): BigInt = - if (supportNativeJsBigInt) JsBigInt.create(value, radix) else CommonBigInt.create(value, radix) - -} - -class JsBigInt internal constructor(private val value: NativeJsBig) : BigInt, BigIntConstructor by JsBigInt { - companion object : BigIntConstructor { - override fun create(value: Int): BigInt = JsBigInt(NativeJsBigInt(value)) - override fun create(value: String, radix: Int): BigInt { - if (value.isEmpty()) { - throw BigIntInvalidFormatException("Zero length BigInteger") - } - if (radix == 10) { - validateRadix(value, radix) - return JsBigInt(NativeJsBigInt(value)) - } - return super.create(value, radix) - } - private fun validateRadix(value: String, radix: Int) { - for (c in value) digit(c, radix) - } - } - - val BigInt.js: dynamic get() = (this as JsBigInt).value.asDynamic() - val Int.js: dynamic get() = NativeJsBigInt(this) - - override val signum: Int get() { - if (js < NativeJsBigInt(0)) return -1 - if (js > NativeJsBigInt(0)) return +1 - return 0 - } - - override fun unaryMinus(): BigInt = JsBigInt(-js) - - override fun inv(): BigInt = JsBigInt(NativeJsInv(js)) - override fun pow(exponent: BigInt): BigInt { - if (exponent.isNegative) throw BigIntNegativeExponentException() - return JsBigInt(NativeJsPow(js, exponent.js)) - } - override fun pow(exponent: Int): BigInt { - if (exponent < 0) throw BigIntNegativeExponentException() - return pow(JsBigInt(NativeJsBigInt(exponent))) - } - - override fun and(other: BigInt): BigInt = JsBigInt(NativeJsAnd(js, other.js)) - override fun or(other: BigInt): BigInt = JsBigInt(NativeJsOr(js, other.js)) - override fun xor(other: BigInt): BigInt = JsBigInt(NativeJsXor(js, other.js)) - - override fun shl(count: Int): BigInt = JsBigInt(NativeJsShl(js, count.js)) - override fun shr(count: Int): BigInt = JsBigInt(NativeJsShr(js, count.js)) - - override fun plus(other: BigInt): BigInt = JsBigInt(this.js + other.js) - override fun minus(other: BigInt): BigInt = JsBigInt(this.js - other.js) - override fun times(other: BigInt): BigInt = JsBigInt(this.js * other.js) - override fun div(other: BigInt): BigInt { - if (other.isZero) throw BigIntDivisionByZeroException() - return JsBigInt(this.js / other.js) - } - override fun rem(other: BigInt): BigInt = JsBigInt(this.js % other.js) - - private val cachedToString by lazy { value.toString() } - - override fun toInt(): Int = NativeJsParseInt(value) - override fun toString(radix: Int): String = js.toString(radix) - override fun toString(): String = cachedToString - - override fun compareTo(other: BigInt): Int = when { - this.js < other.js -> -1 - this.js > other.js -> +1 - else -> 0 - } - - override fun hashCode(): Int = cachedToString.hashCode() - override fun equals(other: Any?): Boolean = other is JsBigInt && this.value == other.value -} diff --git a/kbignum/src/jsMain/kotlin/korlibs/bignumber/ext/NativeJsBigInt.kt b/kbignum/src/jsMain/kotlin/korlibs/bignumber/ext/NativeJsBigInt.kt deleted file mode 100644 index e401500af7..0000000000 --- a/kbignum/src/jsMain/kotlin/korlibs/bignumber/ext/NativeJsBigInt.kt +++ /dev/null @@ -1,22 +0,0 @@ -package korlibs.bignumber.ext - -@JsName("BigInt") -internal external class NativeJsBig - -@JsName("BigInt") -internal external fun NativeJsBigInt(value: String): NativeJsBig -@JsName("BigInt") -internal external fun NativeJsBigInt(value: Number): NativeJsBig -@JsName("parseInt") -internal external fun NativeJsParseInt(value: NativeJsBig): Int - -internal fun NativeJsInv(a: dynamic): dynamic = js("(~(a))") -internal fun NativeJsShl(a: dynamic, b: dynamic): dynamic = js("((a) << (b))") -internal fun NativeJsShr(a: dynamic, b: dynamic): dynamic = js("((a) >> (b))") -internal fun NativeJsXor(a: dynamic, b: dynamic): dynamic = js("((a) ^ (b))") -internal fun NativeJsOr(a: dynamic, b: dynamic): dynamic = js("((a) | (b))") -internal fun NativeJsAnd(a: dynamic, b: dynamic): dynamic = js("((a) & (b))") -//internal fun NativeJsPow(a: dynamic, b: dynamic): dynamic = js("((a) ** (b))") // @TODO: Kotlin.JS Bug -internal val NativeJsPow: dynamic by lazy { eval("(function(a, b) { return a ** b; })") } // by lazy to prevent syntax errors on old browsers - -internal val supportNativeJsBigInt = js("(((typeof globalThis) !== 'undefined') && (typeof (globalThis.BigInt)) !== 'undefined')").unsafeCast() diff --git a/kbignum/src/jvmAndroidMain/kotlin/korlibs/bignumber/BigIntJvm.kt b/kbignum/src/jvmAndroidMain/kotlin/korlibs/bignumber/BigIntJvm.kt deleted file mode 100644 index b9fc1fea44..0000000000 --- a/kbignum/src/jvmAndroidMain/kotlin/korlibs/bignumber/BigIntJvm.kt +++ /dev/null @@ -1,72 +0,0 @@ -package korlibs.bignumber - -import java.math.* - -/** Converts a [BigInteger] into a [BigInt] ([JvmBigInt]) */ -val BigInteger.bi: JvmBigInt get() = JvmBigInt(this) - -/** Converts a [BigInt] into a [BigInteger] */ -fun BigInt.toBigInteger(): BigInteger = when (this) { - is JvmBigInt -> this.value - else -> BigInteger(this.toString()) -} - -actual val BigIntNativeFactory: BigIntConstructor = JvmBigInt - -class JvmBigInt(val value: BigInteger) : BigInt, BigIntConstructor by JvmBigInt { - constructor(value: Int) : this(BigInteger.valueOf(value.toLong())) - constructor(value: Long) : this(BigInteger.valueOf(value)) - constructor(value: String, radix: Int) : this(try { - BigInteger(value, radix) - } catch (e: NumberFormatException) { - throw BigIntInvalidFormatException(e.message ?: "") - }) - companion object : BigIntConstructor { - override fun create(value: Int): BigInt = JvmBigInt(value) - override fun create(value: String, radix: Int): BigInt = JvmBigInt(value, radix) - } - - val BigInt.jvm get() = (this as JvmBigInt).value - val Int.jvm get() = BigInteger.valueOf(this.toLong()) - val Long.jvm get() = BigInteger.valueOf(this) - - override val signum: Int - get() = value.signum() - - override fun unaryPlus(): BigInt = this - override fun unaryMinus(): BigInt = (-value).bi - override fun inv(): BigInt = value.inv().bi - - override fun abs(): BigInt = value.abs().bi - override fun square(): BigInt = (value * value).bi - override fun pow(exponent: BigInt): BigInt { - return pow(exponent.toInt()) - } - override fun pow(exponent: Int): BigInt { - if (exponent < 0) throw BigIntNegativeExponentException() - return (value.pow(exponent)).bi - } - - override fun and(other: BigInt): BigInt = value.and(other.jvm).bi - override fun or(other: BigInt): BigInt = value.or(other.jvm).bi - override fun xor(other: BigInt): BigInt = value.xor(other.jvm).bi - override fun shl(count: Int): BigInt = (value shl count).bi - override fun shr(count: Int): BigInt = (value shr count).bi - - override fun plus(other: BigInt): BigInt = (value + other.jvm).bi - override fun minus(other: BigInt): BigInt = (value - other.jvm).bi - override fun times(other: BigInt): BigInt = (value * other.jvm).bi - override fun div(other: BigInt): BigInt { - if (other.isZero) throw BigIntDivisionByZeroException() - return (value / other.jvm).bi - } - override fun rem(other: BigInt): BigInt = (value % other.jvm).bi - - override fun toInt(): Int = value.toInt() - override fun toString(radix: Int): String = value.toString(radix) - override fun toString(): String = toString(10) - - override fun hashCode(): Int = value.hashCode() - override fun equals(other: Any?): Boolean = if (other is JvmBigInt) value == other.value else false - override fun compareTo(other: BigInt): Int = value.compareTo(other.jvm) -} diff --git a/kbignum/src/jvmTest/kotlin/korlibs/bignumber/BigIntCompareWithJVMTest.kt b/kbignum/src/jvmTest/kotlin/korlibs/bignumber/BigIntCompareWithJVMTest.kt deleted file mode 100644 index 3a5d3f78d4..0000000000 --- a/kbignum/src/jvmTest/kotlin/korlibs/bignumber/BigIntCompareWithJVMTest.kt +++ /dev/null @@ -1,249 +0,0 @@ -package korlibs.bignumber - -import java.math.* -import kotlin.test.* -import kotlin.time.* - -abstract class AbstractBigIntCompareWithJVMTest { - companion object { - private val intItems = listOf( - -9999999, - -8888888, - -0x10001, - -0x10000, - -0xFFFF, - -0xFFFE, - -1024, - -100, - -50, - -16, - -15, - -2, - -1, - 0, - +1, - +2, - +15, - +16, - +50, - +100, - +1024, - +0xFFFE, - +0xFFFF, - +0x10000, - +0x10001, - +8888888, - +9999999 - ) - private val stringItems = listOf( - //"11111111111", - //"1234567890123456789", - //"9191291821821972198723892731927412419757607241902412742141904810123913021931", - //"121231246717581291824912849128509185124190310741841824712837131738172", - ) - - private val allItems = intItems.map { it.toString() } + stringItems - } - - - data class ResultEx(val result: Result, val jvm: String, val kbignum: String) - data class Result(val op: String, val jvm: String, val kbignum: String) - - @Test - fun testSub() = testBinary { jvmL, jvmR, kL, kR -> Result("-", "${jvmL - jvmR}", "${kL - kR}") } - - @Test - fun testAdd() = testBinary { jvmL, jvmR, kL, kR -> Result("+", "${jvmL + jvmR}", "${kL + kR}") } - - @Test - fun testMul() = testBinary { jvmL, jvmR, kL, kR -> Result("*", "${jvmL * jvmR}", "${kL * kR}") } - - @Test - fun testDiv() = - testBinary { jvmL, jvmR, kL, kR -> if (kR != 0.bi) Result("/", "${jvmL / jvmR}", "${kL / kR}") else null } - - @Test - fun testDiv2() { - assertEquals( - "${BigInteger("-9999999") / BigInteger("-65536")}", - "${"-9999999".bi / "-65536".bi}", "-9999999 / -65536" - ) - } - - @Test - fun testRem() = - testBinary { jvmL, jvmR, kL, kR -> if (kR != 0.bi) Result("%", "${jvmL % jvmR}", "${kL % kR}") else null } - - @Test - fun testLeftShift() = - testBinary { jvmL, jvmR, kL, kR -> Result("<<", "${jvmL shl 1024}", "${kL shl 1024}") } - - @Test - fun testLeftShift2() = - testBinary { jvmL, _, kL, _ -> Result("<<", "${jvmL shl 1030}", "${kL shl 1030}") } - - @Test - open fun testRightShift() = testBinary { jvmL, jvmR, kL, kR -> - //Result(">>", "${jvmL / (1 shl 16).toBigInteger()}", "${kL shr 16}") - Result(">>", "${jvmL shr 16}", "${kL shr 16}") - } - - @Test - open fun testRightShift2() = testBinary { jvmL, jvmR, kL, kR -> - //Result(">>", "${jvmL / (1 shl 27).toBigInteger()}", "${kL shr 27}") - Result(">>", "${jvmL shr 27}", "${kL shr 27}") - } - - @Test - fun testBigBig() { - val a = "9191291821821972198723892731927412419757607241902412742141904810123913021931" - val b = "121231246717581291824912849128509185124190310741841824712837131738172" - assertEquals("${BigInteger(a) + BigInteger(b)}", "${a.bi + b.bi}") - assertEquals("${BigInteger(a) + -BigInteger(b)}", "${a.bi + -b.bi}") - assertEquals("${-BigInteger(a) + BigInteger(b)}", "${-a.bi + b.bi}") - assertEquals("${-BigInteger(a) + -BigInteger(b)}", "${-a.bi + -b.bi}") - - assertEquals("${BigInteger(a) - BigInteger(b)}", "${a.bi - b.bi}") - assertEquals("${BigInteger(a) - -BigInteger(b)}", "${a.bi - -b.bi}") - assertEquals("${-BigInteger(a) - BigInteger(b)}", "${-a.bi - b.bi}") - assertEquals("${-BigInteger(a) - -BigInteger(b)}", "${-a.bi - -b.bi}") - - assertEquals("${BigInteger(a) * BigInteger(b)}", "${a.bi * b.bi}") - assertEquals("${BigInteger(a) * -BigInteger(b)}", "${a.bi * -b.bi}") - assertEquals("${-BigInteger(a) * BigInteger(b)}", "${-a.bi * b.bi}") - assertEquals("${-BigInteger(a) * -BigInteger(b)}", "${-a.bi * -b.bi}") - } - - @Test - fun testBigSmall() { - val a = "123678" - val b = "456965" - assertEquals("${BigInteger(a) + BigInteger(b)}", "${a.bi + b.bi}") - assertEquals("${BigInteger(a) - BigInteger(b)}", "${a.bi - b.bi}") - assertEquals("${BigInteger(a) * BigInteger(b)}", "${a.bi * b.bi}") - assertEquals("${BigInteger(a) * -BigInteger(b)}", "${a.bi * -b.bi}") - assertEquals("${-BigInteger(a) * BigInteger(b)}", "${-a.bi * b.bi}") - assertEquals("${-BigInteger(a) * -BigInteger(b)}", "${-a.bi * -b.bi}") - } - - @Test - fun testBigSmall2() { - val a = "192318471586571265712651786924871293164197657612641412412410410" - val b = "1234" - assertEquals("${BigInteger(a) + BigInteger(b)}", "${a.bi + b.bi}") - assertEquals("${BigInteger(a) - BigInteger(b)}", "${a.bi - b.bi}") - assertEquals("${BigInteger(a) * BigInteger(b)}", "${a.bi * b.bi}") - assertEquals("${BigInteger(a) * -BigInteger(b)}", "${a.bi * -b.bi}") - assertEquals("${-BigInteger(a) * BigInteger(b)}", "${-a.bi * b.bi}") - assertEquals("${-BigInteger(a) * -BigInteger(b)}", "${-a.bi * -b.bi}") - } - - @Test - fun testMultCarry() { - var tempJvm = BigInteger.valueOf(0xFFFF) - var temp = 0xFFFF.bi - for (n in 0 until 10) { - tempJvm *= tempJvm - temp *= temp - assertEquals("$tempJvm", "$temp") - } - //println("$tempJvm".length) - //println(BigDecimal("2.0").pow(-1024, MathContext(1024))) - } - - @Test - fun testPow() { - assertEquals("1", "${0.5.bn pow 0}") - assertEquals("0.5", "${0.5.bn pow 1}") - assertEquals("0.25", "${0.5.bn pow 2}") - assertEquals("0.125", "${0.5.bn pow 3}") - assertEquals("0.00000000000000088817841970012523233890533447265625", "${0.5.bn pow 50}") - assertEquals("2", "${0.5.bn pow -1}") - assertEquals("4", "${0.5.bn pow -2}") - assertEquals("8", "${0.5.bn pow -3}") - assertEquals("4294967296", "${2.bn pow 32}") - assertEquals("1125899906842624", "${2.bn pow 50}") - assertEquals( - "5357543035931336604742125245300009052807024058527668037218751941851755255624680612465991894078479290637973364587765734125935726428461570217992288787349287401967283887412115492710537302531185570938977091076523237491790970633699383779582771973038531457285598238843271083830214915826312193418602834034688", - "${2.bn pow 999}" - ) - } - - open fun testBinary(callback: (jvmL: BigInteger, jvmR: BigInteger, kL: BigInt, kR: BigInt) -> Result?) { - val results = arrayListOf() - for (l in allItems) for (r in allItems) { - val jvmL = BigInteger(l) - val jvmR = BigInteger(r) - val kL = l.bi - val kR = r.bi - val res = callback(jvmL, jvmR, kL, kR) ?: continue - results += ResultEx(res, "$jvmL ${res.op} $jvmR", "$kL ${res.op} $kR") - } - assertEquals( - results.joinToString("\n") { "${it.jvm} = ${it.result.jvm}" }, - results.joinToString("\n") { "${it.kbignum} = ${it.result.kbignum}" }, - ) - } - - @Test - fun testMultComplexity() { - //val debug = true - val debug = false - val count = if (debug) 200 else 1 - repeat(count) { n -> - val exp = 1024 * 32 * 2 - val stats = CommonBigInt.OpStats() - val (jvmResult, jvmTime) = measureTimedValue { 10.bi.pow(exp) } - val (nativeResult, nativeTime) = measureTimedValue { CommonBigInt(10).powWithStats(exp, stats) } - if (count > 1) println("$n ($jvmTime/$nativeTime): $stats") - assertEquals(jvmResult.toString(16), nativeResult.toString(16)) - assertEquals(CommonBigInt.OpStats(iterations = 17, bigMultiplications = 1, square = 16), stats) - } - } - - @Test - fun testToString2() { - assertEquals("11000000111001", BigInteger.valueOf(12345).toString(2)) - assertEquals("11000000111001", BigInteger("12345").toString(2)) - assertEquals("3000321", BigInteger("12345").toString(4)) - assertEquals("12345", BigInteger("12345").toString(10)) - assertEquals("3039", BigInteger("12345").toString(16)) - } - - // Big Integer - abstract val Long.bi: BigInt - abstract val Int.bi: BigInt - abstract val String.bi: BigInt - abstract fun String.bi(radix: Int): BigInt -} - -class BigIntCompareWithJVMTestCommon : AbstractBigIntCompareWithJVMTest() { - override val Long.bi: BigInt get() = CommonBigInt(this) - override val Int.bi: BigInt get() = CommonBigInt(this) - override val String.bi: BigInt get() = CommonBigInt(this) - override fun String.bi(radix: Int): BigInt = CommonBigInt(this, radix) - - @Test - override fun testRightShift() = testBinary { jvmL, jvmR, kL, kR -> - Result(">>", "${jvmL / (1 shl 16).toBigInteger()}", "${kL shr 16}") - } - - @Test - override fun testRightShift2() = testBinary { jvmL, jvmR, kL, kR -> - Result(">>", "${jvmL / (1 shl 27).toBigInteger()}", "${kL shr 27}") - } - - @Test - fun testBidirectionalJVMBigIntegerConversion() { - val bigInt = BigInteger("0123456789".repeat(10)) - assertEquals(bigInt, bigInt.bi.toBigInteger()) - assertEquals(bigInt, CommonBigInt(bigInt.toString()).toBigInteger()) - } -} - -class BigIntCompareWithJVMTestJVM : AbstractBigIntCompareWithJVMTest() { - override val Long.bi: BigInt get() = JvmBigInt.create(this) - override val Int.bi: BigInt get() = JvmBigInt.create(this) - override val String.bi: BigInt get() = JvmBigInt.create(this) - override fun String.bi(radix: Int): BigInt = JvmBigInt.create(this, radix) -} diff --git a/kbignum/src/nativeMain/kotlin/korlibs/bignumber/BigIntNative.kt b/kbignum/src/nativeMain/kotlin/korlibs/bignumber/BigIntNative.kt deleted file mode 100644 index 9685fecfd1..0000000000 --- a/kbignum/src/nativeMain/kotlin/korlibs/bignumber/BigIntNative.kt +++ /dev/null @@ -1,3 +0,0 @@ -package korlibs.bignumber - -actual val BigIntNativeFactory: BigIntConstructor = CommonBigInt diff --git a/kbignum/src/wasmMain/kotlin/korlibs/bignumber/BigIntNative.kt b/kbignum/src/wasmMain/kotlin/korlibs/bignumber/BigIntNative.kt deleted file mode 100644 index 9685fecfd1..0000000000 --- a/kbignum/src/wasmMain/kotlin/korlibs/bignumber/BigIntNative.kt +++ /dev/null @@ -1,3 +0,0 @@ -package korlibs.bignumber - -actual val BigIntNativeFactory: BigIntConstructor = CommonBigInt diff --git a/settings.gradle.kts b/settings.gradle.kts index 079f4d801e..87834abbba 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -26,7 +26,6 @@ val inCI = isPropertyTrue("CI") val disabledExtraKorgeLibs = isPropertyTrue("DISABLED_EXTRA_KORGE_LIBS") include(":korcoutines") -include(":kbignum") include(":klock") include(":klogger") include(":korinject")