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);


    }

}
up vote 18 down vote accepted

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;
}
  • 1
    Your method lacks readability, use if statements. – Bhathiya Perera Mar 24 '15 at 3:39
  • 1
    6+2+5 = 12 :O It's typo, right? – D D Mar 24 '15 at 13:52
  • 3
    @Legato your answer is perfect and awesome. I wish if I could give multiple upvotes :D – D D Mar 24 '15 at 13:54
  • 1
    I love that ternary statement, I didn't know you can chain them together like that!! That's awesome. Thanks for your answer man – user3646508 Mar 25 '15 at 0:02
  • 1
    @user3646508 My pleasure. I'm glad my opting to leave it served purpose. Though, I'd caution against ever using more than three, and even then using three scarcely. That's my personal limit; I found it apropo in this case, as the conditionals are short and succinct but as you can see it was still found unreadable. Ultimately, code is the means through which we communicate with other programmers and usually three or more conditions is seen as obfuscation/best replaced by if statements. – Legato Mar 25 '15 at 0:20

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.

  • The string-based approach can handle numbers that don't fit into a long. – Kaz Mar 24 '15 at 16:01
  • @Kaz Not when converted from an int. – Brythan Mar 24 '15 at 18:15
  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;
      }
  • The string-based approach can handle a 500 digit number easily. – Kaz Mar 24 '15 at 16:01
  • @Kaz, Not that I don't agree to a String based approach for a numerical problem. But I wonder where could a 500 digit be applicable. – Ajo Paul Mar 24 '15 at 17:31

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.