Multiplicative Persistance
March 26, 2019
Our per function is a little bit different than Matt’s; it returns the sequence in reverse order:
(define (per n)
(let loop ((n n) (xs (list)))
(if (< n 10)
(cons n xs)
(loop (apply * (digits n))
(cons n xs)))))
Here’s a quick check:
> (per 327) (8 42 327)
Now we can play. The most common ending number, appearing about 90% of the time, is 0:
> (sort (lambda (x y) (< (cdr y) (cdr x)))
(uniq-c = (sort <
(map car (map per (range 1 1000001))))))
((0 . 902609) (6 . 43538) (8 . 32658) (2 . 16673) (4 . 2345)
(5 . 2073) (9 . 56) (3 . 21) (7 . 21) (1 . 6))
The most common number of steps is 1, though 2 is not far behind:
> (sort (lambda (x y) ( < (cdr y) (cdr x)))
(uniq-c = (sort <
(map (lambda (xs) (- (length xs) 1))
(map per (range 1 1000001))))))
((1 . 402540) (2 . 375227) (3 . 123860) (4 . 66772)
(5 . 24654) (6 . 4488) (7 . 2450) (0 . 9))
And here are the records that occur each time a sequence is longer than any previous sequence:
> (let loop ((n 1) (record -1))
(let* ((p (per n)) (len (- (length p) 1)))
(when (< record len)
(display len) (display " ") (display p) (newline))
(loop (+ n 1) (max record len))))
0 (1)
1 (0 10)
2 (0 10 25)
3 (4 14 27 39)
4 (8 18 36 49 77)
5 (6 32 48 168 378 679)
6 (0 20 54 336 768 2688 6788)
7 (0 20 54 336 768 2688 27648 68889)
8 (0 20 54 336 768 2688 27648 338688 2677889)
9 (0 20 54 336 768 2688 27648 338688 4478976 26888999)
10 (0 20 54 336 768 2688 27648 338688 4478976 438939648 3778888999)
11 (0 20 54 336 768 2688 27648 338688 4478976 438939648 4996238671872 277777788888899)
I cheated. I let my computer run for a few hours to compute the records up to 10, then stopped the computation and use the known record for 11. You can run the program at https://ideone.com/Vho12W.
In Python. As suggested in the video only certain patterns of numbers is searched. The results come in a few seconds. After that no more numbers are found up to 50 digits.
from functools import reduce from operator import mul from itertools import combinations_with_replacement def mult(n): pr = [n] while n > 9: n = reduce(mul, (int(c) for c in str(n))) pr.append(n) return pr def search(): """ all solutions start with 2, 3, or 6 rest of the numbers are 6, 7 ,8 ,9 """ first = "23 " rest = "6789" ms = 0 for N in range(2, 50): for f in first: for m in combinations_with_replacement(rest, N + (1 if f == " " else 0)): n = int(f + "".join(m)) steps = mult(n) if len(steps) > ms: ms = len(steps) print("-".join(str(s) for s in steps)) search()Strange. My comment ended up in page 2.??
I also went for a Python solution, this one just enumerates multisets of 2..9 (in appropriate order) and uses the number with those digits in ascending order. A few seconds to get up to 277777788888899 (after looking at 435968 multisets), then nothing. https://oeis.org/A003001 has more details.
from operator import mul from functools import reduce # The smallest number with a given number of steps must have digits # in ascending order and not contain 0 or 1. # Represent candidate numbers by multisets of 0..7: # Convert a multiset to an integer, nth multiset element is number of times # digit n+2 occurs, so eg. [1,2,0,2,0,0,0,1] => 233559 def mset2int(s): return int(''.join([str(i+2)*d for (i,d) in enumerate(s)]) or '0') # Find the next multiset - when converted to integers as above, the # sequence of integers is in ascending order. def nextmultiset(s): # [..,n,0,..,0,m] -> [..,n-1,m+1,..,0,0] # [0,0,..,n] => [n+1,0,..,0] n = s[-1]; s[-1] = 0 for i in range(len(s)-1,0,-1): if s[i-1] > 0: s[i-1] -= 1 s[i] = n+1 return s[0] = n+1 # Count the number of reduction steps for an integer def countsteps(n): count = 0 while n >= 10: n = reduce(mul,(int(d) for d in str(n))) count += 1 return count s = [0]*8 max = -1 while True: n = mset2int(s) steps = countsteps(n) if steps > max: print(n,steps) max = steps nextmultiset(s)I noticed an interesting pattern when I calculated the frequency of the final step in the range 1…10^n
1 occurs n times
3 and 7 occur n(n+1)/2 times
9 occurs n(n+1)(n+2)/6 times
I noticed an interesting pattern when I calculated the frequency of the final step in the range 1…10^n
1 occurs n times
3 and 7 occur n(n+1)/2 times
9 occurs n(n+1)(n+2)/6 times
@Ernie: nice observation, looks like the only numbers going to 1 are 100.., going to 3 are 311.. & permutations, going to 7 are 711.. & permutations and going to 9 are 3311… and 911…, with permutations which gives the result you see. For other numbers to end up here, we would need eg. 311111 to have only 2,3,5 and 7 as prime factors which is (presumably) unlikely, though I don’t see why it should be ruled out.
Investigating further, there seems to only a finite number of fundamentally different numbers that end up at something other than 0. The product of digits can only have 2,3,5 and 7 as prime factors so generating multisets of 0..3 gives us all numbers of that form. We quickly get up to 239 * 33 * 7**2, but after that everything seems to end up at 0:
from operator import mul from functools import reduce def nextmultiset(s): n = s[-1]; s[-1] = 0 for i in range(len(s)-1,0,-1): if s[i-1] > 0: s[i-1] -= 1 s[i] = n+1 return s[0] = n+1 def seq(n): s = [n] while n >= 10: n = reduce(mul,(int(d) for d in str(n))) s += [n] return s def test(): s = [0]*4 while True: n = 2**s[0] * 3**s[1] * 5**s[2] * 7**s[3] a = seq(n) if a[-1] != 0: print(n,s,a) nextmultiset(s) test() """ (1, [0, 0, 0, 0], [1]) (2, [1, 0, 0, 0], [2]) (3, [0, 1, 0, 0], [3]) (5, [0, 0, 1, 0], [5]) (7, [0, 0, 0, 1], [7]) (4, [2, 0, 0, 0], [4]) (6, [1, 1, 0, 0], [6]) (14, [1, 0, 0, 1], [14, 4]) (9, [0, 2, 0, 0], [9]) (15, [0, 1, 1, 0], [15, 5]) ... (3416267673274176, [6, 27, 0, 1], [3416267673274176, 1792336896, 2939328, 23328, 288, 128, 16, 6]) (913217421312, [29, 5, 0, 1], [913217421312, 18144, 128, 16, 6]) (1438916737499136, [24, 6, 0, 6], [1438916737499136, 4444263936, 1492992, 11664, 144, 16, 6]) (112717121716224, [34, 8, 0, 0], [112717121716224, 131712, 42, 8]) (727326941773824, [39, 3, 0, 2], [727326941773824, 1194891264, 124416, 192, 18, 8]) """Here’s a solution in C.
#include <inttypes.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char* argv[]) { if (argc != 2) return EXIT_FAILURE; if (*argv[1] == '-') ++argv[1]; intmax_t x = strtoimax(argv[1], NULL, 10); for (int i = 0;; ++i) { printf("%d %jd\n", i, x); if (x < 9) break; intmax_t y = 1; while (x) { y *= x % 10; x /= 10; } x = y; } return EXIT_SUCCESS; }Example Usage:
Mumps version EN ; ENTER N I,J,N,NS,OLDNS,QTY,VAL K TMP W !,"PER(327) = ",$$PER(327) F I=0:1:9 S TMP(2,I)=0 S OLDNS=-1 F I=1:1:1000001 D . S L=$$PER(I) . S N=$P(L," "),NS=$L(L," ")-1 . S TMP(2,N)=TMP(2,N)+1 . S TMP(3,NS)=$G(TMP(3,NS))+1 . I NS>OLDNS D . . S TMP(4,NS)=L . . S OLDNS=NS F I=2,3 S J=I+.5,N="" F S N=$O(TMP(I,N)) Q:N="" D . S QTY=TMP(I,N) . S TMP(J,-QTY)=$S('$D(TMP(J,-QTY)):N,1:TMP(J,-QTY)_" "_N) F I=2.5,3.5 D . W !!,$P("Common ending #;Common # of steps",";",I-1.5) . S N="" F S N=$O(TMP(I,N)) Q:N="" W !,TMP(I,N),": ",-N W !!,"Longer sequences:" S NS="" F S NS=$O(TMP(4,NS)) Q:NS="" S J=NS W !,$J(NS,2),": ",TMP(4,NS) F I=1000002:1 Q:NS=11 D . S L=$$PER(I),NS=$L(L," ")-1 . I NS>J D . . W:$I(J) !,$J(NS,2),": ",L," ($H = ",$H,")" Q ; PER(N) ; Multiplicative Persistence N I,L,S S L=N F Q:N<10 D . S S=1 . F I=1:1:$L(N) S S=S*$E(N,I) . S N=S,L=N_" "_L Q L ; --- YDB>d ^multpers PER(327) = 8 42 327 Common ending # 0: 902610 6: 43538 8: 32658 2: 16673 4: 2345 5: 2073 9: 56 3 7: 21 1: 6 Common # of steps 1: 402541 2: 375227 3: 123860 4: 66772 5: 24654 6: 4488 7: 2450 0: 9 Longer sequences: 0: 1 1: 0 10 2: 0 10 25 3: 4 14 27 39 4: 8 18 36 49 77 5: 6 32 48 168 378 679 6: 0 20 54 336 768 2688 6788 7: 0 20 54 336 768 2688 27648 68889 8: 0 20 54 336 768 2688 27648 338688 2677889 ($H = 65102,31491) 9: 0 20 54 336 768 2688 27648 338688 4478976 26888999 ($H = 65102,31564) 10: 0 20 54 336 768 2688 27648 338688 4478976 438939648 3778888999 ($H = 65102,43213)^C %YDB-I-CTRLC, CTRL_C encountered YDB>h sdfsdf