OK, got something.
If you look at the last element in your list, lets call it m
. What happens to it it gets multiplied by a and then taken modulo b. It never gets mixed with any other element, so if a configuration of the list has to repeat itself the following must hold:
m*a^n=m modulo b
<==>a^n=1 modulo b
< >a^(n+1)=a modulo b
This is a problem where you can make use of Fermats little theorem
If a and b are coprimes, then
a^phi(b)=1 modulo b
where phi
is Eulers totient function.
So this reduces the amount of list configurations which you have to store in your history drastically. You only have to store it every phi(b)
steps.
I found an implementation of phi here:
Computing Eulers Totient Function
UPDATE:
Ok, I found a quick solution if you were to do += list[i] % b
instead of += list[i] // b
. Otherwise you need b^4*phi(b)
steps in the worst case
UPDATE2:
I rewrote the code in C
(see below) to make it faster and implemented the "tortoise and the hare" algorithm proposed by @user2357112. This way i can check some million loops per second what should be way faster than the python implementation.
I tried it for some different value combinations:
a b steps b^4*phi(b) (b/GCD(b,a))^4*phi(b/GCD(n,a)) (b/GCD(b,a))^4*phi(b/GCD(n,a))/steps
2 37 67469796 67469796 67469796 1
3 37 33734898 67469796 67469796 2
4 37 33734898 67469796 67469796 2
5 37 67469796 67469796 67469796 1
6 37 7496644 67469796 67469796 9
7 37 16867449 67469796 67469796 4
36 37 3748322 67469796 67469796 18
2 36 39366 20155392 629856 16
3 36 256 20155392 82944 27648
4 36 19683 20155392 39366 2
5 36 5038848 20155392 20155392 4
So you see where this is going: The cycle length seems always to be a divisor of (b/GCD(b,a))^4*phi(b/GCD(n,a))
, so the worst case is (b/GCD(b,a))^4*phi(b/GCD(n,a))
steps as suspected
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void modify(int *, int, int);
void printl(int * );
int main(int argc, const char*argv[])
{
int l[5]={1,2,3,4,5};
int lz[5]={1,2,3,4,5};
int i=1,a,b,n;
if (argc<4) {
printf("Not enough arguments!!\n");
exit(1);
}
a=atoi(argv[1]);
b=atoi(argv[2]);
n=atoi(argv[3]);
modify(l,a,b);
while (i<n) {
modify(l,a,b);
modify(l,a,b);
modify(lz,a,b);
i++;
if (memcmp(l,lz,sizeof(l))==0) {
printf("success!\n");
break;
}
if (i%1000000==0) printf("Step %d.000.000\n",i/1000000);
}
printf("Final step: %d\n",i);
printl(l);
printl(lz);
return 0;
}
void modify(int * li, int a, int b) {
int i=0;
while (i<=4) {
li[i]*=a;
i++;
}
i=4;
while (i>=1) {
if (li[i]>=b) {
li[i-1]+=li[i]/b;
}
li[i]=li[i]%b;
i--;
}
li[0]=li[0]%b;
}
void printl(int * li) {
printf("l=(%d,%d,%d,%d,%d)\n",li[0],li[1],li[2],li[3],li[4]);