implement numeric encodings, optimize
This commit is contained in:
89
src/commonMain/kotlin/com/infendro/encoding/util/BigInt.kt
Normal file
89
src/commonMain/kotlin/com/infendro/encoding/util/BigInt.kt
Normal file
@@ -0,0 +1,89 @@
|
||||
package com.infendro.encoding.util
|
||||
|
||||
internal class BigInt private constructor(
|
||||
val words: IntArray,
|
||||
) {
|
||||
init {
|
||||
require(words.isNotEmpty())
|
||||
}
|
||||
|
||||
fun isZero(): Boolean = words.all { it == 0 }
|
||||
|
||||
fun timesAdd(multiplier: Int, addend: Int): BigInt {
|
||||
val product = IntArray(words.size)
|
||||
var carry = addend
|
||||
|
||||
for (i in words.indices) {
|
||||
val current = (words[i].toLong() and 0xFFFFFFFFL) * multiplier + carry
|
||||
product[i] = current.toInt()
|
||||
carry = (current ushr 32).toInt()
|
||||
}
|
||||
|
||||
when {
|
||||
carry > 0 -> {
|
||||
val expanded = product.copyOf(product.size + 1)
|
||||
expanded[product.size] = carry
|
||||
return BigInt(expanded)
|
||||
}
|
||||
else -> return BigInt(product)
|
||||
}
|
||||
}
|
||||
|
||||
fun divRem(divisor: Int): Pair<BigInt, Int> {
|
||||
val quotient = IntArray(words.size)
|
||||
var remainder = 0
|
||||
|
||||
for (i in words.indices.reversed()) {
|
||||
val current = (remainder.toLong() shl 32) or (words[i].toLong() and 0xFFFFFFFFL)
|
||||
quotient[i] = (current / divisor.toLong()).toInt()
|
||||
remainder = (current % divisor.toLong()).toInt()
|
||||
}
|
||||
|
||||
when {
|
||||
quotient.size > 1 && quotient.last() == 0 -> {
|
||||
val contracted = quotient.copyOfRange(0, quotient.size - 1)
|
||||
return Pair(BigInt(contracted), remainder)
|
||||
}
|
||||
else -> return Pair(BigInt(quotient), remainder)
|
||||
}
|
||||
}
|
||||
|
||||
fun toByteArray(): ByteArray {
|
||||
val msw = words.last()
|
||||
val mswBytes = when {
|
||||
(msw ushr 24) != 0 -> 4
|
||||
(msw ushr 16) != 0 -> 3
|
||||
(msw ushr 8) != 0 -> 2
|
||||
else -> 1
|
||||
}
|
||||
val size = ((words.size - 1) * 4) + mswBytes
|
||||
val result = ByteArray(size)
|
||||
|
||||
for (i in 0..<size) {
|
||||
val index = size - 1 - i
|
||||
val shift = (index % 4) * 8
|
||||
result[i] = (words[index / 4] ushr shift).toByte()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
companion object {
|
||||
val zero: BigInt
|
||||
get() = BigInt(intArrayOf(0))
|
||||
|
||||
fun from(value: ByteArray): BigInt {
|
||||
val size = value.size.divCeil(4)
|
||||
val words = IntArray(size)
|
||||
|
||||
for (i in value.indices) {
|
||||
val byte = value[i].toInt() and 0xFF
|
||||
val index = value.lastIndex - i
|
||||
val shift = (index % 4) * 8
|
||||
words[index / 4] = words[index / 4] or (byte shl shift)
|
||||
}
|
||||
|
||||
return BigInt(words)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user