Recursion

Armstrong Numbers
Armstrong Numbers in Scala
import scala.annotation.tailrec;

import math.{log10, pow}

object ArmstrongNumbers {

  def isArmstrongNumber(num: Int): Boolean =
    if (num < 10) true
    else {
      val len: Double = log10(num).toInt + 1

      @tailrec
      def recurMe(nbr: Int, total: Double): Boolean =
        nbr match {
          case 0 => total == num
          case n => recurMe(n / 10, total + pow(n % 10, len))
        }
        
      recurMe(num, 0.0)
    }

}

This approach starts by importing from packages for what is needed.

The isArmstrongNumber() method uses an if and else expression. Given that the test input is never less than 1, if the input Int is less than 10, then true is returned. Otherwise the result of the else expression is returned.

The else expression starts by using the log10() method to calculate the number of digits in the input Int.

Then a nested function (also called a closure) is defined which takes two arguments. The first argument is for the number that is being calculated. The second number is for totaling the results of the calculations.

Note

Although the number of digits is not passed into the inner function, the inner function still has access to it. It is said that the value for the number of digits is captured by the inner function.

The nested function is annotated with the @tailrec annotation to verify that the function can be compiled with tail call optimization.

A tail call is a particular form of recursion where the last call in the method is a call to the same function and nothing else.

In other words, if the last call in recurMe() is recurMe(arg1, arg2) + 1, the + 1 makes the recursion non-tail recursive.

If the last call in recurMe() is recurMe(arg1, arg2, acc + 1), then the recursion is a tail call, because only the function is being called with no other operation being peformed on it.

A match is used to do pattern-matching on the first argument number. If the number has calculated down to 0, then the nested function returns whether the total equals the original number. Otherwise, the nested function calls itself with the recalculated number and the new total. Note that no state is being modified, so the recursive approach supports immutability.

Since pow() take two Double arguments, the length of the String was set to the Double type to keep from doing a widening conversion of Int to Double on every call to pow().

Finally, the inner function is called, passing in the original number and a Double value of 0.0 for the total. The isArmstrongNumber() method returns the result of calling its recursive inner function.

9th Oct 2024 · Found it useful?