Calculate Digital Root

Posted on

Problem

Here’s my solution for finding the digital root of a number. Just for purposes of completion, a digital root is:

“If you take the digits of any number and add them together, and then
add the digits of the resulting number together, and continue doing
that until you get a single digit, that single digit is the digital
root of the original number.”

What I was hoping for, is if you guys could take a look and provide a cleaner solution. I’m trying to better myself for an upcoming competition.

import java.util.Scanner;
import java.util.StringTokenizer;


public class DigialRoot {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        System.out.print("Enter a number: ");
        System.out.println();

        String str = sc.nextLine();
        String[] numbers = str.split("");
        int[] myList = new int[numbers.length];
        for(int i=0; i < numbers.length; i++){
            myList[i] = Integer.parseInt(numbers[i]);
        }
        //add all numbers together
        int sum = 0;        
        for(Integer x : myList){
            sum += x;
        }

        //break down and add sum
        String sumStr = Integer.toString(sum);
        String[] nums = sumStr.split("");
        int[] nxtList = new int[nums.length];
        for(int i=0; i < nums.length; i++){
            nxtList[i] = Integer.parseInt(nums[i]);
        }

        //calculating final result of digital root
        int result = 0;
        for(Integer x : nxtList){
            result += x;
        }

        System.out.println("Original number: " + str);
        System.out.println("Digital root: " + result);


    }

}

Solution

Since a digital root is obtained by adding all the digits in a number, and while the resulting number is more than 9, repeating the process, an alternative and equally effective approach could simply be dividing by 9. In most cases, the digital root is simply the remainder of this operation.

Here’s an example to see this in action. Take any number; for simplicity’s sake, I choose a relatively low number: 625.

625 ->
6 + 2 + 5 = 13 ->
1 + 3 = 4

Thus the digital root is 4.

If you divided 625 by 9 you would get 69 with a remainder of 4. In other words, using modulo, and factoring in our edge cases (When n is 0, or 9 divides n with no remainder), we can write a digital root computing method as straight-forward as:

public static int computeDigitalRoot(int n) {
    return n == 0 ? 0 : 
           n % 9 == 0 ? 9 : n % 9;
}

If the ternary operator is not to your liking, this is the equivalent using if statements:

public static int computeDigitalRoot(int n) {
    if (n == 0) {
        return 0;
    }
    if (n % 9 == 0) {
        return 9;
    }
    return n % 9;
}

Bug

Try it with an input like

9999999999999999999999999999999999999999999999999999999999999999999999999999

and it will return a multiple digit result.

You need to keep reducing it until its done. You can’t just reduce twice and stop.

Simpler way to add the digits of a string

Rather than splitting the string, you can just convert the string to a character array and add it from there.

public static long addDigits(String number) {
    long sum = 0;        
    for ( char digit : number.toCharArray() ) {
        if ( ! Character.isDigit(digit) ) {
            throw new IllegalArgumentException("Character not a digit in " + number);
        }

        sum += digit - '0';
    }

    return sum;
}

This also saves a lot of calls to parseInt to convert a single character into a number. You can make it slightly faster by changing to

        sum += digit;
    }

    return sum - '0' * number.length();
}

But that also makes it run out of space to hold the sum sooner.

Conversion to String unnecessary

You have a method to add the digits in a string, so you use it twice. However, the second time you don’t have a string, so you convert the number into a string. Consider the following:

    private final static int BASE = 10;

    private static long reduce(long number) {
        while ( number > BASE ) {
            long digit = number % BASE;
            number /= BASE;
            number += digit;
        }

        return number;
    }

This takes a number and reduces it a single digit. It can handle any number that will fit in a long. It adds in a different order than your version, but it will give the same result.

  1. The logic of the code. It looks like your algorithm is not correct. The problem statement clearly says that the process should be repeated until we get one digit, but you compute the sum of digits only twice(what if still turns out to be greater than 9?). You can use a recursive method to make your work for all possible cases(or you can keep iterating until the root is found).

  2. Modularity and separation of concerns. It is not a good practice to have one method that does everything. I’d recommend creating a separate method that computes the digit root so that the main method is responsible only for the I/O.

A more traditional and recursive approach. Keep checking the remainder and add it to sum, till you find a single digit.

public int getDigitalRoot(int number){

        int sum = 0;
        int tempNumber = number;
        int mod = 0;
        while(tempNumber > 0){
          mod = tempNumber %10;
          sum+=mod;
          tempNumber=tempNumber/10;
        }
        if(sum/10 != 0){
          return getDigitalRoot(sum);
        }
        return sum;
      }

Leave a Reply

Your email address will not be published. Required fields are marked *