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);
 }
}
Legato
9,9294 gold badges50 silver badges118 bronze badges
asked Mar 23, 2015 at 23:17
\$\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;
}
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
answered Mar 24, 2015 at 3:08
\$\endgroup\$
5
  • 1
    \$\begingroup\$ Your method lacks readability, use if statements. \$\endgroup\$ Commented Mar 24, 2015 at 3:39
  • 1
    \$\begingroup\$ 6+2+5 = 12 :O It's typo, right? \$\endgroup\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented 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.

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

answered Mar 24, 2015 at 0:44
\$\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;
 }
answered Mar 24, 2015 at 12:22
\$\endgroup\$
2
  • \$\begingroup\$ The string-based approach can handle a 500 digit number easily. \$\endgroup\$ Commented 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\$ Commented Mar 24, 2015 at 17:31

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.