1. Overview

When we work with Kotlin, we often need to manipulate numerical data.

In this tutorial, we’ll explore how to reverse a number in Kotlin.

2. Introduction to the Problem

Reversing a number means rearranging its digits in the opposite order. For instance, if we have the number 12345, reversing it would produce 54321. Of course, if the input number has trailing zeros, such as 1000, we expect the reversed integer to have leading zeros cut. For example, after reversing 1000, we should have 1 as the result.

For simplicity, we’ll only focus on positive integers in this tutorial. Also, we’ll use unit test asserts to verify whether each approach yields the expected result.

3. Using the ‘*/‘ and ‘%*‘ Operators

The first idea to solve this problem is to use arithmetic operations.

First, we initialize the reversed result variable as 0. Then, we use a loop to repeatedly divide the input number by 10, adding the remainder to the current result x 10 in each iteration until the input number becomes 0:

Reversed = 0
    1230456 / 10 = 123045 Remainder: 6, Reversed: 0 x 10 + 6 = 6
|->  123045 / 10 = 12304 Remainder: 5, Reversed: 6 x 10 + 5 = 65
|->   12304 / 10 = 1230 Remainder: 4, Reversed: 65 x 10 + 4 = 654
|->    1230 / 10 = 123 Remainder: 0, Reversed: 654 x 10 + 0 = 6540
|->     123 / 10 = 12 Remainder: 3, Reversed: 6540 x 10 + 3 = 65403
|->      12 / 10 = 1 Remainder: 2, Reversed: 65403 x 10 + 2 = 654032
|->       1 / 10 = 0 Remainder: 1, Reversed: 654032 x 10 + 1 = 6540321
Reversed = 6540321

So next, let’s translate this idea into Kotlin code using the division operator ‘*/‘ and the modulus operator ‘%*‘:

fun reverseNumber(number: Int): Int {
    var n = number
    var result = 0
    while (n > 0) {
        result = 10 * result + n % 10
        n = n / 10
    }
    return result
}

Next, let’s verify whether our reverseNumber() function does the job:

val rev1 = reverseNumber(1230456)
assertEquals(6540321, rev1)

val rev2 = reverseNumber(10000)
assertEquals(1, rev2)

4. Improving the reverseNumber() Function

Kotlin provides many great features that allow us to write idiomatic code. For example, we can turn our function into an extension function so that it can be called more fluently and naturally:

fun Int.reverse(): Int {
    var n = this
    var result = 0
    while (n > 0) {
        result = 10 * result + n % 10
        n = n / 10
    }
    return result
}

Now, we can call the method naturally, such as 1234.reverse():

val rev1 = 1234.reverse()
assertEquals(4321, rev1)
                          
val rev2 = 10000.reverse()
assertEquals(1, rev2)

5. Handling Integer Overflow

So far, we’ve solved the problem by creating a pretty convenient reverse() function. However, an edge case we haven’t talked about is integer overflow.

We know that the max value of Kotlin’s Int is 2,147,483,647 (2 31 – 1). Also, after reversing an Int, the result can be greater than the Int.MAX_VALUE, for example:

Input    : 1234123409
Reversed : 9043214321
Max Int  : 2147483647

Therefore, we must handle this edge case to ensure the function provides reliable results.

A simple way to check if overflow happened is to declare the result variable as Long and check if the result after each loop step is greater than Int.MAX_VALUE:

fun Int.reverse2(): Int {
    var n = this
    var result = 0L
    while (n > 0) {
        result = 10 * result + n % 10
        require(result <= Int.MAX_VALUE) { "Cannot reverse ${this@reverse2}! Cause: Int overflow" }
        n = n / 10
    }
    return result.toInt()
}

As the code above shows, we use the require() function to perform the overflow check and raise IllegalArgumentException when an overflow occurs.

Next, let’s write a test to make sure it throws the expected exception when overflow occurs:

assertThrows<IllegalArgumentException> { 1234123409.reverse2() }.also {
    assertEquals("Cannot reverse 1234123409! Cause: Int overflow", it.message)
}

6. Using String Transformation

We’ve seen how to solve the problem with a mathematical approach. Alternatively, we can reverse a number through string manipulation.

Kotlin’s String class offers the reverse() function, allowing us to reverse a string quickly. Therefore, we can first convert the input number to a string, then call the standard reverse() function, and finally convert the string back to an Int.

Of course, we shouldn’t forget to handle the overflow case:

fun Int.reverse3(): Int {
    val longNum = "$this".reversed().toLong()
    require(longNum <= Int.MAX_VALUE) { "Cannot revers $this! Cause: Int overflow" }
    return longNum.toInt()
}

Finally, let’s test the string transformation approach reverse3():

val rev1 = 1234.reverse3()
assertEquals(4321, rev1)

val rev2 = 10000.reverse3()
assertEquals(1, rev2)

assertThrows<IllegalArgumentException> { 1234123409.reverse3() }.also {
    assertEquals("Cannot revers 1234123409! Cause: Int overflow", it.message)
}

7. Conclusion

In this article, we learned two approaches to reversing a positive integer. Further, we discussed the integer overflow case and saw through examples how to handle it.

As always, the complete source code for the examples is available over on GitHub.