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);
}
}
4 Answers 4
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\$\begingroup\$ Your method lacks readability, use if statements. \$\endgroup\$JaDogg– JaDogg2015年03月24日 03:39:52 +00:00Commented Mar 24, 2015 at 3:39
-
1\$\begingroup\$ 6+2+5 = 12 :O It's typo, right? \$\endgroup\$SSC– SSC2015年03月24日 13:52:38 +00:00Commented 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– SSC2015年03月24日 13:54:50 +00:00Commented 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\$user3646508– user36465082015年03月25日 00:02:30 +00:00Commented 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– Legato2015年03月25日 00:20:46 +00:00Commented Mar 25, 2015 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.
-
\$\begingroup\$ The string-based approach can handle numbers that don't fit into a
long
. \$\endgroup\$Kaz– Kaz2015年03月24日 16:01:56 +00:00Commented Mar 24, 2015 at 16:01 -
\$\begingroup\$ @Kaz Not when converted from an
int
. \$\endgroup\$Brythan– Brythan2015年03月24日 18:15:32 +00:00Commented Mar 24, 2015 at 18:15
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).
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;
}
-
\$\begingroup\$ The string-based approach can handle a 500 digit number easily. \$\endgroup\$Kaz– Kaz2015年03月24日 16:01:32 +00:00Commented 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– Ajo Paul2015年03月24日 17:31:28 +00:00Commented Mar 24, 2015 at 17:31