12
\$\begingroup\$

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


    }

}
\$\endgroup\$
0

4 Answers 4

18
\$\begingroup\$

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;
}
\$\endgroup\$
5
  • 1
    \$\begingroup\$ Your method lacks readability, use if statements. \$\endgroup\$
    – JaDogg
    Mar 24, 2015 at 3:39
  • 1
    \$\begingroup\$ 6+2+5 = 12 :O It's typo, right? \$\endgroup\$
    – SSC
    Mar 24, 2015 at 13:52
  • 3
    \$\begingroup\$ @Legato your answer is perfect and awesome. I wish if I could give multiple upvotes :D \$\endgroup\$
    – SSC
    Mar 24, 2015 at 13:54
  • 1
    \$\begingroup\$ I love that ternary statement, I didn't know you can chain them together like that!! That's awesome. Thanks for your answer man \$\endgroup\$ Mar 25, 2015 at 0:02
  • 1
    \$\begingroup\$ @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. \$\endgroup\$
    – Legato
    Mar 25, 2015 at 0:20
6
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ The string-based approach can handle numbers that don't fit into a long. \$\endgroup\$
    – Kaz
    Mar 24, 2015 at 16:01
  • \$\begingroup\$ @Kaz Not when converted from an int. \$\endgroup\$
    – Brythan
    Mar 24, 2015 at 18:15
5
\$\begingroup\$
  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.

\$\endgroup\$
0
\$\begingroup\$

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;
      }
\$\endgroup\$
2
  • \$\begingroup\$ The string-based approach can handle a 500 digit number easily. \$\endgroup\$
    – Kaz
    Mar 24, 2015 at 16:01
  • \$\begingroup\$ @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. \$\endgroup\$
    – Ajo Paul
    Mar 24, 2015 at 17:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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