Digital root/Multiplicative digital root: Difference between revisions

From Rosetta Code
Content added Content deleted
m (Fix task description to match example)
(J)
Line 217: Line 217:
8 8 18 24 29 36
8 8 18 24 29 36
9 9 19 33 91 119</pre>
9 9 19 33 91 119</pre>

=={{header|J}}==

First, we need something to split a number into digits:

<lang J> 10&#.inv 123321
1 2 3 3 2 1</lang>

Second, we need to find their product:

<lang J> */@(10&#.inv) 123321
36</lang>

Then we use this inductively until it converges:

<lang J> */@(10&#.inv)^:a: 123321
123321 36 18 8</lang>

MP is one less than the length of this list, and MDR is the last element of this list:

<lang J> (<:@#,{:) */@(10&#.inv)^:a: 123321
3 8
(<:@#,{:) */@(10&#.inv)^:a: 7739
3 8
(<:@#,{:) */@(10&#.inv)^:a: 893
3 2
(<:@#,{:) */@(10&#.inv)^:a: 899998
2 0</lang>

For the table, we don't need that whole list, we only need the final value. Then prepend with counting numbers and use these values to classify the original argument (taking the first five from each group):

<lang J> (5&{./.~ (*/@(10&#.inv)^:_)"0) i.20000
0 10 20 25 30
1 11 111 1111 11111
2 12 21 26 34
3 13 31 113 131
4 14 22 27 39
5 15 35 51 53
6 16 23 28 32
7 17 71 117 171
8 18 24 29 36
9 19 33 91 119</lang>

Note that since the first 10 non-negative integers are single digit values, the first column here doubles as a label (representing the corresponding multiplicative digital root).


=={{header|Python}}==
=={{header|Python}}==

Revision as of 08:46, 20 April 2014

Digital root/Multiplicative digital root is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

The multiplicative digital root (MDR) and multiplicative persistence (MP) of a number (N) is calculated rather like the Digital root except digits are multiplied:

  • Set MDR to N and MP to 0
  • While MDR has more than one digit:
  • Find a replacement MDR as the multiplication of the digits of the current MDR
  • Increment MP
  • Return MP and MDR
Task
  • Tabulate the MP and MDR of the numbers 123321, 7739, 893, 899998
  • Tabulate MDR versus the first five numbers having that MDR, something like:
MP: [n0..n4]
==  ========
 0: [0, 10, 20, 25, 30]
 1: [1, 11, 111, 1111, 11111]
 2: [2, 12, 21, 26, 34]
 3: [3, 13, 31, 113, 131]
 4: [4, 14, 22, 27, 39]
 5: [5, 15, 35, 51, 53]
 6: [6, 16, 23, 28, 32]
 7: [7, 17, 71, 117, 171]
 8: [8, 18, 24, 29, 36]
 9: [9, 19, 33, 91, 119]

Show all output on this page.

References

D

Translation of: Python

<lang d>import std.stdio, std.algorithm, std.typecons, std.range, std.conv;

/// Multiplicative digital root. auto mdRoot(in int n) pure /*nothrow*/ {

   auto mdr = [n];
   while (mdr.back > 9)
       mdr ~= reduce!q{a * b}(1, mdr.back.text.map!(d => d - '0'));
       //mdr ~= mdr.back.text.map!(d => d - '0').mul;
       //mdr ~= mdr.back.reverseDigits.mul;
   return tuple(mdr.length - 1, mdr.back);

}

void main() {

   "Number: (MP, MDR)\n======  =========".writeln;
   foreach (immutable n; [123321, 7739, 893, 899998])
       writefln("%6d: (%s, %s)", n, n.mdRoot[]);
   auto table = 10.iota.zip((int[]).init.repeat).assocArray;
   auto n = 0;
   while (table.byValue.map!walkLength.reduce!min < 5) {
       table[n.mdRoot[1]] ~= n;
       n++;
   }
   "\nMP: [n0..n4]\n==  ========".writeln;
   foreach (const mp; table.byKey.array.sort())
       writefln("%2d: %s", mp, table[mp].take(5));

}</lang>

Output:
Number: (MP, MDR)
======  =========
123321: (3, 8)
  7739: (3, 8)
   893: (3, 2)
899998: (2, 0)

MP: [n0..n4]
==  ========
 0: [0, 10, 20, 25, 30]
 1: [1, 11, 111, 1111, 11111]
 2: [2, 12, 21, 26, 34]
 3: [3, 13, 31, 113, 131]
 4: [4, 14, 22, 27, 39]
 5: [5, 15, 35, 51, 53]
 6: [6, 16, 23, 28, 32]
 7: [7, 17, 71, 117, 171]
 8: [8, 18, 24, 29, 36]
 9: [9, 19, 33, 91, 119]

Alternative Version

<lang d>import std.stdio, std.algorithm, std.typecons, std.range;

uint digitsProduct(uint n) pure nothrow {

   typeof(return) result = !!n;
   while (n) {
       result *= n % 10;
       n /= 10;
   }
   return result;

}

/// Multiplicative digital root. Tuple!(size_t, uint) mdRoot(uint m) pure nothrow {

   auto mdr = m
              .recurrence!((a, n) => a[n - 1].digitsProduct)
              .until!q{ a <= 9 }(OpenRight.no).array;
   return tuple(mdr.length - 1, mdr.back);

}

void main() {

   "Number: (MP, MDR)\n======  =========".writeln;
   foreach (immutable n; [123321, 7739, 893, 899998])
       writefln("%6d: (%s, %s)", n, n.mdRoot[]);
   auto table = 10.iota.zip((int[]).init.repeat).assocArray;
   auto n = 0;
   while (table.byValue.map!walkLength.reduce!min < 5) {
       table[n.mdRoot[1]] ~= n;
       n++;
   }
   "\nMP: [n0..n4]\n==  ========".writeln;
   foreach (const mp; table.byKey.array.sort())
       writefln("%2d: %s", mp, table[mp].take(5));

}</lang>

More Efficient Version

<lang d>import std.stdio, std.algorithm, std.range;

/// Multiplicative digital root. uint[2] mdRoot(in uint n) pure nothrow {

   uint mdr = n;
   uint count = 0;
   while (mdr > 9) {
       uint m = mdr;
       uint digitsMul = !!m;
       while (m) {
           digitsMul *= m % 10;
           m /= 10;
       }
       mdr = digitsMul;
       count++;
   }
   return [count, mdr];

}

void main() {

   "Number: [MP, MDR]\n======  =========".writeln;
   foreach (immutable n; [123321, 7739, 893, 899998])
       writefln("%6d: %s", n, n.mdRoot);
   auto table = 10.iota.zip((uint[]).init.repeat).assocArray;
   auto n = 0;
   while (table.byValue.map!walkLength.reduce!min < 5) {
       table[n.mdRoot[1]] ~= n;
       n++;
   }
   "\nMP: [n0..n4]\n==  ========".writeln;
   foreach (const mp; table.byKey.array.sort())
       writefln("%2d: %s", mp, table[mp].take(5));

}</lang> The output is similar.

Haskell

Note that in the function mdrNums we don't know in advance how many numbers we'll need to examine to find the first 5 associated with all the MDRs. Using a lazy array to accumulate these numbers allows us to keep the function simple. <lang haskell>import Control.Arrow import Data.Array import Data.LazyArray import Data.List (unfoldr) import Data.Tuple import Text.Printf

-- The multiplicative persistence (MP) and multiplicative digital root (MDR) of -- the argument. mpmdr :: Integer -> (Int, Integer) mpmdr = (length *** head) . span (> 9) . iterate (product . digits)

-- Pairs (mdr, ns) where mdr is a multiplicative digital root and ns are the -- first k numbers having that root. mdrNums :: Int -> [(Integer, [Integer])] mdrNums k = assocs $ lArrayMap (take k) (0,9) [(snd $ mpmdr n, n) | n <- [0..]]

digits :: Integral t => t -> [t] digits 0 = [0] digits n = unfoldr step n

 where step k = if k == 0 then Nothing else Just (swap $ quotRem k 10)

printMpMdrs :: [Integer] -> IO () printMpMdrs ns = do

 putStrLn "Number MP MDR"
 putStrLn "====== == ==="
 sequence_ [printf "%6d %2d %2d\n" n p r | n <- ns, let (p,r) = mpmdr n]

printMdrNums:: Int -> IO () printMdrNums k = do

 putStrLn "MDR Numbers"
 putStrLn "=== ======="
 let showNums = unwords . map show
 sequence_ [printf "%2d  %s\n" mdr $ showNums ns | (mdr,ns) <- mdrNums k]

main :: IO () main = do

 printMpMdrs [123321, 7739, 893, 899998]
 putStrLn ""
 printMdrNums 5</lang>
Output:

Note that the values in the first column of the table are MDRs, as shown in the task's sample output, not MP as incorrectly stated in the task statement and column header.

Number MP MDR
====== == ===
123321  3  8
  7739  3  8
   893  3  2
899998  2  0

MDR Numbers
=== =======
 0  0 10 20 25 30
 1  1 11 111 1111 11111
 2  2 12 21 26 34
 3  3 13 31 113 131
 4  4 14 22 27 39
 5  5 15 35 51 53
 6  6 16 23 28 32
 7  7 17 71 117 171
 8  8 18 24 29 36
 9  9 19 33 91 119

J

First, we need something to split a number into digits:

<lang J> 10&#.inv 123321 1 2 3 3 2 1</lang>

Second, we need to find their product:

<lang J> */@(10&#.inv) 123321 36</lang>

Then we use this inductively until it converges:

<lang J> */@(10&#.inv)^:a: 123321 123321 36 18 8</lang>

MP is one less than the length of this list, and MDR is the last element of this list:

<lang J> (<:@#,{:) */@(10&#.inv)^:a: 123321 3 8

  (<:@#,{:) */@(10&#.inv)^:a: 7739

3 8

  (<:@#,{:) */@(10&#.inv)^:a: 893

3 2

  (<:@#,{:) */@(10&#.inv)^:a: 899998

2 0</lang>

For the table, we don't need that whole list, we only need the final value. Then prepend with counting numbers and use these values to classify the original argument (taking the first five from each group):

<lang J> (5&{./.~ (*/@(10&#.inv)^:_)"0) i.20000 0 10 20 25 30 1 11 111 1111 11111 2 12 21 26 34 3 13 31 113 131 4 14 22 27 39 5 15 35 51 53 6 16 23 28 32 7 17 71 117 171 8 18 24 29 36 9 19 33 91 119</lang>

Note that since the first 10 non-negative integers are single digit values, the first column here doubles as a label (representing the corresponding multiplicative digital root).

Python

Python: Inspired by the solution to the Digital root task

<lang python>try:

   from functools import reduce

except:

   pass

def mdroot(n):

   'Multiplicative digital root'
   mdr = [n]
   while mdr[-1] > 9:
       mdr.append(reduce(int.__mul__, (int(dig) for dig in str(mdr[-1])), 1))
   return len(mdr) - 1, mdr[-1]

if __name__ == '__main__':

   print('Number: (MP, MDR)\n======  =========')
   for n in (123321, 7739, 893, 899998):
       print('%6i: %r' % (n, mdroot(n)))
       
   table, n = {i: [] for i in range(10)}, 0
   while min(len(row) for row in table.values()) < 5:
       mpersistence, mdr = mdroot(n)
       table[mdr].append(n)
       n += 1
   print('\nMP: [n0..n4]\n==  ========')
   for mp, val in sorted(table.items()):
       print('%2i: %r' % (mp, val[:5]))</lang>
Output:
Number: (MP, MDR)
======  =========
123321: (3, 8)
  7739: (3, 8)
   893: (3, 2)
899998: (2, 0)

MP: [n0..n4]
==  ========
 0: [0, 10, 20, 25, 30]
 1: [1, 11, 111, 1111, 11111]
 2: [2, 12, 21, 26, 34]
 3: [3, 13, 31, 113, 131]
 4: [4, 14, 22, 27, 39]
 5: [5, 15, 35, 51, 53]
 6: [6, 16, 23, 28, 32]
 7: [7, 17, 71, 117, 171]
 8: [8, 18, 24, 29, 36]
 9: [9, 19, 33, 91, 119]

Python: Inspired by the more efficient version of D.

Substitute the following function to run twice as fast when calculating mdroot(n) with n in range(1000000). <lang python>def mdroot(n):

   count, mdr = 0, n 
   while mdr > 9:
       m, digitsMul = mdr, 1
       while m:
           m, md = divmod(m, 10)
           digitsMul *= md
       mdr = digitsMul
       count += 1
   return count, mdr</lang>
Output:

(Exactly the same as before).