I want to convert large positive BigIntegers (up to many thousands of digits) to strings in Kotlin, using number bases up to 100 (and possibly higher).
For bases ≤36, there is of course toString(base), but for larger bases, I wrote this extension function:
fun BigInteger.toStringX(base: Int): String {
if (base <= 36) return toString(base) // improve speed if base <= 36
val bigBase = base.toBigInteger()
var n = this
val stringBuilder = StringBuilder()
while (n > ZERO) {
val div = n.divideAndRemainder(bigBase)
stringBuilder.append(DIGITS[div[1].toInt()])
n = div[0]
}
return stringBuilder.reverse().toString()
}
where DIGITS is a string containing the list of digits.
Now the native toString is faster by about an order of magnitude than my function – e.g. 60 ms for about 10,000 digits vs. 500 ms. Why is my function so slow? Any help improving on its speed (while maintinaing the ability to convert to bases > 36) would be appreciated.
(By the way, replacing append() with insert() and losing reverse() in the last line doesn't change much.)
Looking at the source code for the built-in
toString, it seems to call this privatetoString, which implements a divide-and-conquer algorithm.This means that there is only O(log(N)) divisions, for an N-bit number. Compare this to your algorithm, which does O(N) divisions.
So for large numbers, you can implement this algorithm too - "split" the number up into smaller ones, then use your O(N) algorithm when they are small enough, all the while passing the string builder along, so the digits are appended.