Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Completes kbignum documentation + adds a BigInt.toBigInteger in the JVM/Android targets #1636

Merged
merged 1 commit into from
May 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
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")
15 changes: 14 additions & 1 deletion kbignum/src/commonMain/kotlin/korlibs/bignumber/BigNum.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,19 @@ class BigNum(val int: BigInt, val scale: Int) : Comparable<BigNum> {
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
Expand All @@ -70,8 +75,10 @@ class BigNum(val int: BigInt, val scale: Int) : Comparable<BigNum> {
return BigNum(res, this.scale) * BigNum(1.bi, precision)
}

infix fun pow(other: Int) = pow(other, 32)
/** 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)
Expand All @@ -91,6 +98,7 @@ class BigNum(val int: BigInt, val scale: Int) : Comparable<BigNum> {
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
Expand Down Expand Up @@ -122,18 +130,23 @@ class BigNum(val int: BigInt, val scale: Int) : Comparable<BigNum> {
}
}

/** 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)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ package korlibs.bignumber

import java.math.*

val BigInteger.bi get() = JvmBigInt(this)
/** 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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,13 @@ class BigIntCompareWithJVMTestCommon : AbstractBigIntCompareWithJVMTest() {
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() {
Expand Down