Digital root/Multiplicative digital root
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 MP versus the first five numbers having that MP, 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
- Multiplicative Digital Root on Wolfram Mathworld.
- Multiplicative digital root on Wikipedia.
- Multiplicative digital root on The On-Line Encyclopedia of Integer Sequences.
D
<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.
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).