74 lines
2.2 KiB
Kotlin
74 lines
2.2 KiB
Kotlin
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 bytes = ByteArray((words.size * 4) - words.last().countLeadingZeroBytes())
|
|
for (i in bytes.indices) {
|
|
val (wi, bi) = (bytes.lastIndex - i).divRem(4)
|
|
bytes[i] = (words[wi] ushr (bi * 8)).toByte()
|
|
}
|
|
return bytes
|
|
}
|
|
|
|
companion object {
|
|
val zero: BigInt
|
|
get() = BigInt(intArrayOf(0))
|
|
|
|
fun from(bytes: ByteArray): BigInt {
|
|
val words = IntArray(bytes.size.divCeil(4))
|
|
for (i in bytes.indices) {
|
|
val (wi, bi) = (bytes.lastIndex - i).divRem(4)
|
|
words[wi] = words[wi] or ((bytes[i].toInt() and 0xFF) shl (bi * 8))
|
|
}
|
|
return BigInt(words)
|
|
}
|
|
}
|
|
}
|