File tree Expand file tree Collapse file tree 12 files changed +171
-2
lines changed
androidMain/kotlin/io/github/observeroftime/kbigint
androidUnitTest/kotlin/io/github/observeroftime/kbigint
commonMain/kotlin/io/github/observeroftime/kbigint
commonTest/kotlin/io/github/observeroftime/kbigint
jsMain/kotlin/io/github/observeroftime/kbigint
jsTest/kotlin/io/github/observeroftime/kbigint
jvmMain/kotlin/io/github/observeroftime/kbigint
jvmTest/kotlin/io/github/observeroftime/kbigint
nativeMain/kotlin/io/github/observeroftime/kbigint
nativeTest/kotlin/io/github/observeroftime/kbigint Expand file tree Collapse file tree 12 files changed +171
-2
lines changed Original file line number Diff line number Diff line change @@ -5,6 +5,8 @@ package io.github.observeroftime.kbigint
55import android.annotation.TargetApi
66import android.os.Build.VERSION_CODES
77import java.math.BigInteger
8+ import kotlin.math.floor
9+ import kotlin.math.log2
810
911/* * A multiplatform implementation of a big integer. */
1012actual class KBigInt private constructor(private var value : BigInteger ) : Comparable<KBigInt> {
@@ -130,6 +132,27 @@ actual class KBigInt private constructor(private var value: BigInteger) : Compar
130132 @Throws(ArithmeticException ::class )
131133 actual infix fun pow (n : Int ) = KBigInt (value.pow(n))
132134
135+ /* *
136+ * Compute the integer logarithm base [b] of the number.
137+ *
138+ * @since 0.5.0
139+ * @throws [ArithmeticException] if `this <= 0 || b < 2`
140+ */
141+ @ExperimentalMultiplatform
142+ @Throws(ArithmeticException ::class )
143+ actual infix fun log (b : Int ): Int {
144+ if (value.signum() < 1 || b <= 1 )
145+ throw ArithmeticException (" Non-positive KBigInt or base < 2" )
146+
147+ val guess = floor((bitLength - 1 ) / log2(b.toDouble())).toInt()
148+ val base = BigInteger .valueOf(b.toLong())
149+ val lowerBound = base.pow(guess)
150+
151+ return if (lowerBound > value) guess - 1
152+ else if (lowerBound.multiply(base) <= value) guess + 1
153+ else guess
154+ }
155+
133156 /* *
134157 * Compute the approximate square root of the value.
135158 *
Original file line number Diff line number Diff line change @@ -90,6 +90,21 @@ actual class KBigIntTest {
9090 assertEquals(KBigInt (" 4611686018427387904" ), long pow 2 )
9191 }
9292
93+ @Test
94+ @OptIn(ExperimentalMultiplatform ::class )
95+ actual fun testLog () {
96+ assertEquals(3 , KBigInt (10 ) log 2 )
97+ assertEquals(20 , KBigInt (" 100000000000000000000" ) log 10 )
98+
99+ assertFailsWith(ArithmeticException ::class ) {
100+ KBigInt (- 1 ) log 2
101+ }
102+
103+ assertFailsWith(ArithmeticException ::class ) {
104+ KBigInt (2 ) log 1
105+ }
106+ }
107+
93108 @Test
94109 actual fun testSqrt () {
95110 assertEquals(KBigInt (46340 ), long.sqrt())
Original file line number Diff line number Diff line change @@ -102,7 +102,19 @@ expect class KBigInt : Comparable<KBigInt> {
102102 */
103103 infix fun pow (n : Int ): KBigInt
104104
105- /* * Compute the approximate square root of the value. */
105+ /* *
106+ * Compute the integer logarithm base [b] of the number.
107+ *
108+ * @since 0.5.0
109+ * @throws [ArithmeticException] if `this <= 0 || b < 2`
110+ */
111+ infix fun log (b : Int ): Int
112+
113+ /* *
114+ * Compute the approximate square root of the value.
115+ *
116+ * @throws [ArithmeticException] if the value is negative
117+ */
106118 fun sqrt (): KBigInt
107119
108120 /* *
Original file line number Diff line number Diff line change @@ -16,6 +16,7 @@ expect class KBigIntTest {
1616 fun testGcdLcm ()
1717 fun testPow ()
1818 fun testSqrt ()
19+ fun testLog ()
1920 fun testAbs ()
2021 fun testCompare ()
2122 fun testEquals ()
Original file line number Diff line number Diff line change @@ -102,6 +102,23 @@ export function pow(value, n) {
102102 return value ** BigInt ( n ) ;
103103}
104104
105+ /**
106+ * Compute the base `b` integer logarithm of the value.
107+ *
108+ * @param {bigint } value
109+ * @param {number } b
110+ * @returns {number }
111+ */
112+ export function log ( value , b ) {
113+ const guess = ( ( bitLength ( value ) - 1 ) / Math . log2 ( b ) ) | 0 ;
114+ const base = BigInt ( b )
115+ const lowerBound = base ** BigInt ( guess ) ;
116+
117+ if ( lowerBound > value ) return guess - 1 ;
118+ if ( lowerBound * base <= value ) return guess + 1 ;
119+ return guess ;
120+ }
121+
105122/**
106123 * Convert a {@link BigInt} to an {@link Int8Array}.
107124 *
Original file line number Diff line number Diff line change @@ -2,7 +2,7 @@ package io.github.observeroftime.kbigint
22
33/* * A multiplatform implementation of a big integer. */
44@JsExport
5- @Suppress(" UNUSED_VARIABLE " )
5+ @Suppress(" UnusedVariable " , " unused " )
66@OptIn(ExperimentalStdlibApi ::class , ExperimentalJsExport ::class )
77actual class KBigInt private constructor(@JsExternalArgument private var value : BigInt ) : Comparable<KBigInt> {
88 /* * Convert a [String] to a [KBigInt]. */
@@ -186,6 +186,19 @@ actual class KBigInt private constructor(@JsExternalArgument private var value:
186186 return KBigInt (KBigIntUtils .pow(value, n))
187187 }
188188
189+ /* *
190+ * Compute the integer logarithm base [b] of the number.
191+ *
192+ * @since 0.5.0
193+ * @throws [ArithmeticException] if `this <= 0 || b < 2`
194+ */
195+ @ExperimentalMultiplatform
196+ actual infix fun log (b : Int ): Int {
197+ if (sign < 1 || b <= 1 )
198+ throw ArithmeticException (" Non-positive KBigInt or base < 2" )
199+ return KBigIntUtils .log(value, b)
200+ }
201+
189202 /* *
190203 * Compute the approximate square root of the value.
191204 *
Original file line number Diff line number Diff line change 1+ @file:Suppress(" unused" )
2+
13package io.github.observeroftime.kbigint
24
35internal external class BigInt {
@@ -17,6 +19,7 @@ internal external object KBigIntUtils {
1719 fun cmp (a : BigInt , b : BigInt ): Int
1820 fun gcd (a : BigInt , b : BigInt ): BigInt
1921 fun pow (value : BigInt , n : Int ): BigInt
22+ fun log (value : BigInt , b : Int ): Int
2023 fun toByteArray (value : BigInt ): ByteArray
2124 fun fromByteArray (bytes : ByteArray ): BigInt
2225}
Original file line number Diff line number Diff line change @@ -91,6 +91,21 @@ actual class KBigIntTest {
9191 assertEquals(KBigInt (" 4611686018427387904" ), long pow 2 )
9292 }
9393
94+ @Test
95+ @OptIn(ExperimentalMultiplatform ::class )
96+ actual fun testLog () {
97+ assertEquals(3 , KBigInt (10 ) log 2 )
98+ assertEquals(20 , KBigInt (" 100000000000000000000" ) log 10 )
99+
100+ assertFailsWith(ArithmeticException ::class ) {
101+ KBigInt (- 1 ) log 2
102+ }
103+
104+ assertFailsWith(ArithmeticException ::class ) {
105+ KBigInt (2 ) log 1
106+ }
107+ }
108+
94109 @Test
95110 @OptIn(ExperimentalMultiplatform ::class )
96111 actual fun testSqrt () {
Original file line number Diff line number Diff line change 33package io.github.observeroftime.kbigint
44
55import java.math.BigInteger
6+ import kotlin.math.floor
7+ import kotlin.math.log2
68
79/* * A multiplatform implementation of a big integer. */
810actual class KBigInt private constructor(private var value : BigInteger ) : Comparable<KBigInt> {
@@ -128,6 +130,27 @@ actual class KBigInt private constructor(private var value: BigInteger) : Compar
128130 @Throws(ArithmeticException ::class )
129131 actual infix fun pow (n : Int ) = KBigInt (value.pow(n))
130132
133+ /* *
134+ * Compute the integer logarithm base [b] of the number.
135+ *
136+ * @since 0.5.0
137+ * @throws [ArithmeticException] if `this <= 0 || b < 2`
138+ */
139+ @ExperimentalMultiplatform
140+ @Throws(ArithmeticException ::class )
141+ actual infix fun log (b : Int ): Int {
142+ if (value.signum() < 1 || b <= 1 )
143+ throw ArithmeticException (" Non-positive KBigInt or base < 2" )
144+
145+ val guess = floor((bitLength - 1 ) / log2(b.toDouble())).toInt()
146+ val base = BigInteger .valueOf(b.toLong())
147+ val lowerBound = base.pow(guess)
148+
149+ return if (lowerBound > value) guess - 1
150+ else if (lowerBound.multiply(base) <= value) guess + 1
151+ else guess
152+ }
153+
131154 /* *
132155 * Compute the approximate square root of the value.
133156 *
Original file line number Diff line number Diff line change 11package io.github.observeroftime.kbigint
22
33import kotlin.test.*
4+ import kotlin.test.Test
45
56actual class KBigIntTest {
67 companion object {
@@ -90,6 +91,21 @@ actual class KBigIntTest {
9091 assertEquals(KBigInt (" 4611686018427387904" ), long pow 2 )
9192 }
9293
94+ @Test
95+ @OptIn(ExperimentalMultiplatform ::class )
96+ actual fun testLog () {
97+ assertEquals(3 , KBigInt (10 ) log 2 )
98+ assertEquals(20 , KBigInt (" 100000000000000000000" ) log 10 )
99+
100+ assertFailsWith(ArithmeticException ::class ) {
101+ KBigInt (- 1 ) log 2
102+ }
103+
104+ assertFailsWith(ArithmeticException ::class ) {
105+ KBigInt (2 ) log 1
106+ }
107+ }
108+
93109 @Test
94110 actual fun testSqrt () {
95111 assertEquals(KBigInt (46340 ), long.sqrt())
You can’t perform that action at this time.
0 commit comments