Skip to content

Commit 64b5bbe

Browse files
feat(core): implement bitLength & bitCount
1 parent c0d0f3a commit 64b5bbe

13 files changed

Lines changed: 200 additions & 3 deletions

File tree

kbigint/src/androidMain/kotlin/io/github/observeroftime/kbigint/KBigInt.kt

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,30 @@ actual class KBigInt private constructor(private var value: BigInteger) : Compar
1313

1414
actual constructor(number: Long) : this(number.toBigInteger())
1515

16-
/** Convert a [ByteArray] to a [KBigInt]. */
1716
actual constructor(bytes: ByteArray) : this(BigInteger(bytes))
1817

1918
@get:JvmName("signum")
2019
actual val sign: Int
2120
get() = value.signum()
2221

22+
/**
23+
* The total number of bits in the value.
24+
*
25+
* @see [BigInteger.bitLength]
26+
*/
27+
@get:JvmName("bitLength")
28+
actual val bitLength: Int
29+
get() = value.bitLength()
30+
31+
/**
32+
* The number of set bits in the value.
33+
*
34+
* @see [BigInteger.bitCount]
35+
*/
36+
@get:JvmName("bitCount")
37+
actual val bitCount: Int
38+
get() = value.bitCount()
39+
2340
@JvmName("add")
2441
actual operator fun plus(other: KBigInt) = KBigInt(value + other.value)
2542

@@ -113,6 +130,10 @@ actual class KBigInt private constructor(private var value: BigInteger) : Compar
113130
*/
114131
fun toDouble() = value.toDouble()
115132

116-
/** Convert the value to a [ByteArray]. */
133+
/**
134+
* Convert the value to a [ByteArray].
135+
*
136+
* @see [BigInteger.toByteArray]
137+
*/
117138
actual fun toByteArray(): ByteArray = value.toByteArray()
118139
}

kbigint/src/androidUnitTest/kotlin/io/github/observeroftime/kbigint/KBigIntTest.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,26 @@ actual class KBigIntTest {
1515
assertEquals(-1, KBigInt(-2).sign)
1616
}
1717

18+
@Test
19+
actual fun testBits() {
20+
val a = KBigInt(1024)
21+
val b = KBigInt(-1024)
22+
val c = KBigInt(0)
23+
val d = KBigInt(-1)
24+
25+
assertEquals(11, a.bitLength)
26+
assertEquals(1, a.bitCount)
27+
28+
assertEquals(10, b.bitLength)
29+
assertEquals(10, b.bitCount)
30+
31+
assertEquals(0, c.bitLength)
32+
assertEquals(0, c.bitCount)
33+
34+
assertEquals(0, d.bitLength)
35+
assertEquals(0, d.bitCount)
36+
}
37+
1838
@Test
1939
actual fun testArithmetic() {
2040
assertEquals(KBigInt("9223372039002259456"), string + long)

kbigint/src/commonMain/kotlin/io/github/observeroftime/kbigint/KBigInt.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ expect class KBigInt : Comparable<KBigInt> {
2323
*/
2424
val sign: Int
2525

26+
/** The total number of bits in the value. */
27+
val bitLength: Int
28+
29+
/** The number of set bits in the value. */
30+
val bitCount: Int
31+
2632
/** Add two [KBigInt] values. */
2733
operator fun plus(other: KBigInt): KBigInt
2834

kbigint/src/commonTest/kotlin/io/github/observeroftime/kbigint/KBigIntTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ internal const val OVER_MAX_LONG = "9223372036854775808"
55

66
expect class KBigIntTest {
77
fun testSign()
8+
fun testBits()
89
fun testArithmetic()
910
fun testIncDec()
1011
fun testNegate()

kbigint/src/javascript/kbigint-utils.mjs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,32 @@ export function sign(value) {
1010
return cmp(value, 0n);
1111
}
1212

13+
/**
14+
* Count the total number of bits in the value.
15+
*
16+
* @param value {bigint}
17+
* @return {number}
18+
* @see https://stackoverflow.com/a/76616288/21974435
19+
*/
20+
export function bitLength(value) {
21+
const n = value >= 0n ? value : ~value;
22+
const i = (n.toString(16).length - 1) >> 2;
23+
return i + 32 - Math.clz32(Number(n >> BigInt(i)))
24+
}
25+
26+
/**
27+
* Count the number of set bits in the value.
28+
*
29+
* @param value {bigint}
30+
* @return {number}
31+
* @see https://stackoverflow.com/a/72518920/21974435
32+
*/
33+
export function bitCount(value) {
34+
let n = (value >= 0n ? value : ~value), bits;
35+
for (bits = 0; n > 0n; ++bits) n &= n - 1n;
36+
return bits
37+
}
38+
1339
/**
1440
* Return the absolute value.
1541
*

kbigint/src/jsMain/kotlin/io/github/observeroftime/kbigint/KBigInt.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ actual class KBigInt private constructor(@JsExternalArgument private var value:
2020
actual val sign: Int
2121
get() = KBigIntUtils.sign(value)
2222

23+
actual val bitLength: Int
24+
get() = KBigIntUtils.bitLength(value)
25+
26+
actual val bitCount: Int
27+
get() = KBigIntUtils.bitCount(value)
28+
2329
@JsName("add")
2430
actual operator fun plus(other: KBigInt): KBigInt {
2531
val a = this.value

kbigint/src/jsMain/kotlin/io/github/observeroftime/kbigint/KBigIntUtils.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ internal external object KBigIntUtils {
1010
fun sqrt(value: BigInt): BigInt
1111
fun abs(value: BigInt): BigInt
1212
fun sign(value: BigInt): Int
13+
fun bitLength(value: BigInt): Int
14+
fun bitCount(value: BigInt): Int
1315
fun cmp(a: BigInt, b: BigInt): Int
1416
fun pow(value: BigInt, n: Int): BigInt
1517
fun toByteArray(value: BigInt): ByteArray

kbigint/src/jsTest/kotlin/io/github/observeroftime/kbigint/KBigIntTest.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,26 @@ actual class KBigIntTest {
1515
assertEquals(-1, KBigInt(-2).sign)
1616
}
1717

18+
@Test
19+
actual fun testBits() {
20+
val a = KBigInt(1024)
21+
val b = KBigInt(-1024)
22+
val c = KBigInt(0)
23+
val d = KBigInt(-1)
24+
25+
assertEquals(11, a.bitLength)
26+
assertEquals(1, a.bitCount)
27+
28+
assertEquals(10, b.bitLength)
29+
assertEquals(10, b.bitCount)
30+
31+
assertEquals(0, c.bitLength)
32+
assertEquals(0, c.bitCount)
33+
34+
assertEquals(0, d.bitLength)
35+
assertEquals(0, d.bitCount)
36+
}
37+
1838
@Test
1939
actual fun testArithmetic() {
2040
assertEquals(KBigInt("9223372039002259456"), string + long)

kbigint/src/jvmMain/kotlin/io/github/observeroftime/kbigint/KBigInt.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,30 @@ actual class KBigInt private constructor(private var value: BigInteger) : Compar
1111

1212
actual constructor(number: Long) : this(number.toBigInteger())
1313

14-
/** Convert a [ByteArray] to a [KBigInt]. */
1514
actual constructor(bytes: ByteArray) : this(BigInteger(bytes))
1615

1716
@get:JvmName("signum")
1817
actual val sign: Int
1918
get() = value.signum()
2019

20+
/**
21+
* The total number of bits in the value.
22+
*
23+
* @see [BigInteger.bitLength]
24+
*/
25+
@get:JvmName("bitLength")
26+
actual val bitLength: Int
27+
get() = value.bitLength()
28+
29+
/**
30+
* The number of set bits in the value.
31+
*
32+
* @see [BigInteger.bitCount]
33+
*/
34+
@get:JvmName("bitCount")
35+
actual val bitCount: Int
36+
get() = value.bitCount()
37+
2138
@JvmName("add")
2239
actual operator fun plus(other: KBigInt) = KBigInt(value + other.value)
2340

kbigint/src/jvmTest/kotlin/io/github/observeroftime/kbigint/KBigIntTest.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,26 @@ actual class KBigIntTest {
1515
assertEquals(-1, KBigInt(-2).sign)
1616
}
1717

18+
@Test
19+
actual fun testBits() {
20+
val a = KBigInt(1024)
21+
val b = KBigInt(-1024)
22+
val c = KBigInt(0)
23+
val d = KBigInt(-1)
24+
25+
assertEquals(11, a.bitLength)
26+
assertEquals(1, a.bitCount)
27+
28+
assertEquals(10, b.bitLength)
29+
assertEquals(10, b.bitCount)
30+
31+
assertEquals(0, c.bitLength)
32+
assertEquals(0, c.bitCount)
33+
34+
assertEquals(0, d.bitLength)
35+
assertEquals(0, d.bitCount)
36+
}
37+
1838
@Test
1939
actual fun testArithmetic() {
2040
assertEquals(KBigInt("9223372039002259456"), string + long)

0 commit comments

Comments
 (0)