implement numeric encodings, optimize

This commit is contained in:
2026-01-17 12:27:41 +01:00
parent 45d74d9cff
commit 55faf1d670
22 changed files with 355 additions and 249 deletions

View 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)
}
}
}