views:

1458

answers:

22

A digital root, according to Wikipedia, is "the number obtained by adding all the digits, then adding the digits of that number, and then continuing until a single-digit number is reached."

For instance, the digital root of 99 is 9, because 9 + 9 = 18 and 1 + 8 = 9.

My Haskell solution -- and I'm no expert -- is as follows.

digitalRoot n
    | n < 10 = n
    | otherwise = digitalRoot . sum . map (\c -> read [c]) . show $ n

As a language junky, I'm interested in seeing solutions in as many languages as possible, both to learn about those languages and possibly to learn new ways of using languages I already know. (And I know at least a bit of quite a few.) I'm particularly interested in the tightest, most elegant solutions in Haskell and REBOL, my two principal "hobby" languages, but any ol' language will do. (I pay the bills with unrelated projects in Objective C and C#.)

Here's my (verbose) REBOL solution:

digital-root: func [n [integer!] /local added expanded] [
    either n < 10 [
        n
    ][
        expanded: copy []
        foreach c to-string n [
            append expanded to-integer to-string c
        ]
        added: 0
        foreach e expanded [
            added: added + e
        ]
        digital-root added
    ]
]

EDIT:

As some have pointed out either directly or indirectly, there's a quick one-line expression that can calculate this. You can find it in several of the answers below and in the linked Wikipedia page. (I've awarded Varun the answer, as the first to point it out.) Wish I'd known about that before, but we can still bend our brains with this question by avoiding solutions that involve that expression, if you're so inclined. If not, Crackoverflow has no shortage of questions to answer. :)

+12  A: 

On applying my mind, it is evident that digital root is nothing but remainder of the number when divided by 9, or 9 if remainder is zero So my C# solution is

public class DigitalRoot
{
   public static int GetDigitalRoot(long inputNumber)
   {
      if (inputNumber%9==0)
           return 9;
      else
           return inputNumber%9;
   }
}

My Java solution will be the same(Do tell if there is some sublte mistake because with java, I had not done anything in last 2 years)

public class DigitalRoot
{
   public static int GetDigitalRoot(long inputNumber)
   {
      if (inputNumber%9==0)
           return 9;
      else
           return inputNumber%9;
   }
}
Varun Mahajan
The digital root of 18, according to your reasoning, would be 0 because 18 divided by 9 yields 2 with a remainder of 0. However, the digital root as defined by Revolucent would be 9.
Thomas Owens
Thomas, you beat me to it! But Varun has shown that there's another way to calculate the digital root, as long as you account for numbers evenly divisible by 9.
Gregory Higley
The code has been modified according to suggestions. I don't know why negative vote?
Varun Mahajan
Ah. His initial explanation (before he added the code) did not say what to do if num%9 == 0. I would have to test it, but it looks better now.
Thomas Owens
Also, I did not downvote, as I assumed that you were missing the case, as it worked for most numbers that I thought of and tried.
Thomas Owens
@Varun I voted it down when you first answered because it was incomplete. It looks better now so I removed the downvote.
Mark Biek
You could also use return ( (inputNumber-1) % 9 ) + 1; to keep it as a one-liner.
stevemegson
This fails for 0 unless dr(0) is 9 by definition...
Vinko Vrsalovic
A: 

PHP

So I initially waaaay over-thought this... Seems like it can be done in PHP with a ternary operator as follows:

function getDigitalRoot($n)
{
    // Don't forget to allow for 0
    return (($n%9) == 0 && ($n != 0) )? 9: $n%9;
}


Function below entered initially before brain kicked into gear :)

function getDigitalRoot($n)
{
    while($n>9)
    {
        // Create array from the digits
        $vals = str_split($n);
        // Sum up the array. If it's not a single digit, we'll loop again
        $n = array_sum($vals);
    }
    return n;
}

Edit

Thanks to a comment from Unknwntech, function str_split will split a string into an array without the need for a delimiter, removing the kludgy for loop from my example above.

Input: 99
Output: 9

Input: 102
Output: 3
ConroyP
I believe you can access the elements of a string using an array. $n[0] would give you the first character in the string, $n[1] the second, and so on. That might make your code cleaner (and perhaps more optimized).
Thomas Owens
I don't know if you still can, but in PHP4 you could do the following... <?php $valueAsString = "123789"; echo $valueAsString[0]; // outputs 1 echo $valueAsString[3]; // outputs 7 ?>May help...
ZombieSheep
Tried that, but it seems not to work so well in PHP5 :( Thanks for the suggestions though. Turns out that this problem is far less complicated than I originally thought, ternary operator can do the job handily enough.
ConroyP
BTW to split a sting into an array use str_split($string) its output is an array.
Unkwntech
@Unknwntech - Thanks for the pointer, much appreciated, answer updated!
ConroyP
+1  A: 

A Python attempt

def dr(x):
  if x < 10: return x
  return dr(sum(int(c) for c in str(x)))

The optimal solution is not fun to write... I thought the idea was to show off languages, and the % operator is hardly showing off anything. Maybe it was the wrong problem...

The other solutions fail for 0. Unless dr(0) is defined as 9... Though I didn't get that from the textual definition.

def dr2(x):
  if x == 0: return 0
  if x % 9 == 0: return 9
  else: return x % 9
Vinko Vrsalovic
assert n >= 0
J.F. Sebastian
+2  A: 

Terse Perl (golfed solution courtesy of BKB):

while($n>9){my$t;for(split//,$n){$t+=$_}$n=$t}

(More) legible Perl:

while ($number > 9) {
   my $total;
   for $digit (split(//,$number)) {
       $total += $digit
   }
   $number=$total;
}

I was tempted to import sum from List::Util. :)

UPDATE: Varun's (most best) response, in terse Perl:

$n=($n%9?$n%9:9);
Adam Bellaire
Had to up-vote you as your code was identical to mine, even down to the variable names! (One exception: I prefer 'foreach' when looping over a list.)
Stephen Darlington
@Stephen, as do I, I have to admit I was golfing a bit at first. :)
Adam Bellaire
Golfed: while($n>9){my$t;for(split//,$n){$t+=$_}$n=$t}
I would like to point out that in Perl6 foreach is renamed for, and the classic for(;;) is renamed loop(;;).
Brad Gilbert
A: 

Forgive the lack of code examples, but I wanted to provide a simpler approach to the solution.

A simple solution is to parse through the digits one at a time, adding them up. As soon as the cumulative sum exceeds 9, subtract 9 and carry on with the addition.

This solves for the digital root in a single pass.

brianb
+3  A: 

From the wikipedia page you link in your question: the digital root of n is given by (1+((n-1) mod 9)).

From there it's just a matter of syntax (and using sane big integer libraries if you're doing this for very large numbers :) )

moonshadow
Yeah, I guess I should have read the whole article. :)
Gregory Higley
+1  A: 

Thanks to Varun, my new Haskell solution is:

digitalRoot n
    | m9 == 0 = 9
    | otherwise = m9
    where
        m9 = n `mod` 9
Gregory Higley
Your initial version returns 0 for 0; this version returns 9 for 0 which one to believe?
J.F. Sebastian
A: 

C# Recursive

int DigitalRoot(int number)
{
    if ( number < 10) return number;
    else
    {
        int counter = 0; int h = 0; 
        for (int f = 10; number / (f / 10) > 0; f *= 10)
        {
            counter += ((number % f) - h) / (f / 10);
            h = number % f;
        }
        return DigitalRoot(counter);
    }
}

Or. even better:

int DigitalRoot(int number)
{
    return number % 9 == 0 ? 9 : number % 9;
}
DrJokepu
A: 

ruby attempt

def digitalRoot(n)
   s = n.to_i.to_s
   while (s.length > 1) do
      result = 0
      s.each do |d|
        result += d.to_i
      end
      s = result.to_i.to_s
   end
   return s.to_i
end
workmad3
+11  A: 
smink
As I mentioned to moonshadow, I somehow missed that little equation. Oh well, we can still have fun with it for a bit.
Gregory Higley
J.F. Sebastian
A: 

more concise ruby attempt

def digitalRoot(n)
  return 1 + ((n.to_i - 1) % 9)
end
workmad3
-1 % 9 == 8 in Ruby therefore digitalRoot(0) will return 9 instead of 0.
J.F. Sebastian
+1  A: 

Varun's idea implemented in Scala:

def dr(n:Int) = (n % 9) match {case 0 => 9; case x => x}
ePharaoh
A: 

In python, single pass:

def digitalRoot(n):
    sum = 0
    for d in str(n):
        sum += int(d)
        if sum > 9: sum -= 9
    return sum

and as a single-liner with the mod 9 solution:

def digitalRoot(n):
    return 0 if n==0 else 1+((n-1)%9)
Yuval A
The special case for n == 0 is unnecessary; 1+((0-1)%9) = 1+(-1%9) = 1+(-1) = 0
Lucas Oman
A: 

PHP

<?php
function digitalRoot($num)
 {
    while($num > 9)
     {
        $num = array_sum(str_split($num));
     }
    return $num;
 }
echo digitalRoot('65536');
?>
Unkwntech
+1  A: 

Here's a recursive C solution. This doesn't try to be the shortest possible solution, but rather a sensible, readable one. If a recursive solution using snprintf() can be called "sensible", when a O(1) solution one-liner has been shown to exist, that is. :)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned int digital_root(const char *string)
{
        int i;
        unsigned int v = 0;

        /* Add all digits. */
        for(i = 0; isdigit(string[i]); i++)
                v += string[i] - '0';

        /* Recursion necessary? */
        if(v >= 10)
        {
                char buf[32];
                snprintf(buf, sizeof buf, "%u", v);
                return digital_root(buf);
        }
        return v;
}

int main(int argc, char *argv[])
{
        int i;

        for(i = 1; argv[i] != NULL; i++)
                printf("%s: %u\n", argv[i], digital_root(argv[i]));
        return EXIT_SUCCESS;
}
unwind
Well, since the one-liner ended up being pretty boring, I'm more interested in seeing this kind of stuff. I love interesting syntax (weirdo that I am), and one-liners don't have a whole lot, unless a language can do something in one line that simply can't be duplicated in another language.
Gregory Higley
A: 

Ruby

def digitalSum(n)
  return 1+((n-1)%9)
end
Lucas Oman
In Ruby (-1 % 9) == 8 therefore digitalSum(0) == 9 but it must be dr(0) == 0.
J.F. Sebastian
A: 

Perl 6

  • Procedural:

    sub digitalroot ( $number is copy ){
      while ($number > 9) {
        $number = [+] split( "", $number );
      }
      return $number;
    }
    
  • Functional:

    multi digitalroot ( $number where{ .perl >= 10 } ){
      return digitalroot( [+] split( "", $number ) );
    }
    multi digitalroot ( $number where{ .perl <= 9  } ){
      return $number;
    }
    
  • Terse:

    $n=($n%9??$n%9!!9);
    
Brad Gilbert
I was just thinking that the subroutines needed to be edited to reflect the changes in the Perl6 spec, when I realized that the terse version, is the only version I am sure will always work, regardless of any future changes in the spec.
Brad Gilbert
+1  A: 

Common Lisp

Digital root by modulus method:

(defun digital-root (x)
  (setf x (1+ (mod (- x 1) 9))))
Phil
+1  A: 

Windows Batch File

Strict approach:

@echo off
setlocal enabledelayedexpansion  

set /a number  = %1
set /a droot = 0

:loop
rem Sum up digits
if %number% leq 0 goto check
set /a droot += !number! %% 10
set /a number ^/= 10
goto loop

:check
rem Got a single-digit number?
if %droot% leq 9 goto end

rem Do one more pass
set /a number = droot
set /a droot = 0
goto loop

:end
echo %droot%

Single pass (using brianb's approach):

@echo off
setlocal enabledelayedexpansion

set /a number = %1
set /a droot = 0

:loop
if %number% leq 0 goto end
set /a droot += !number! %% 10
if !droot! gtr 9 set /a droot -= 9
set /a number ^/= 10
goto loop

:end
echo %droot%

Digital root formula implementation:

@set /a dr = (%1 - 1) %% 9 + 1
@echo %dr%

Usage:

>digitalroot.bat 42
6
>digitalroot.bat 256
4
Helen
A: 

If divide N by 9 the remainder will equal digital root. Why do we need such complicated codes for this straightforward operation?

examples:

632/9 = 70 remainder 2 = dr(2) 22/9 = 2 r 4 = dr(4) 18/9 = 2 r 0 (if zero then digital root is 9)

Tina
+1  A: 

C# LINQ Recursive Extension Method

This might not be the most efficient since there's a lot of type conversion going on, but it's fun :-).

public static int DigitalRoot(this int source)
{
    int result = 
        source.ToString().ToCharArray().Sum(x => int.Parse(x.ToString()));
    return (result > 9) ? result.DigitalRoot() : result;
}
Ben McCormack
A: 

Here's a solution in J, a language I'm now stuffing into my brain. Just learned about gerunds and decided to put them to use:

digitalSum =: monad : '(]`9: @. (0: = ]))"0 (9|y)'

I edited this question and completely changed my answer because my old solution worked only with atoms, and didn't play well with arguments of any shape. This one does. I've learned a lot about J in the brief time between my previous edit and this one.

Gregory Higley