I am not sure of the correct mathematical name of the feature I am looking at. Its been a long time since I did math at school. https://en.wikipedia.org/wiki/Multiplicative_group_of_integers_modulo_n seems to concerned with this sort of thing, but leaves me unsure that I have understood what is written.
Below I use '%' as MOD and '^' as 'raised to the power of'. And am quite wordy.
For all primes > 2, there is a sequence {2^n%prime, for all integer n, 0 to infinity}. That is { 2^0 % prime = 1, 2^1 % prime = 2, .. 2^(prime-1) % prime = 1, 2^prime % prime = 2, ..} 2^((prime-1) * m)%prime = 1 and 2^(prime * m)%prime = 2 for all integer m.
if the prime is 7 however, the sequence is made up of two instance of a shorter sequence thus: 2^0%7 = 1, 2^1%7 = 2, 2^2%7 = 4, 2^3%7 = 1, 2^4%7 = 2, 2^5%7 = 4, 2^6%7 = 1 and then 2^(6 * n)%7 is still 1; but the are extra values that are also another set of at (2^(3+6*n)%7)
So the cycle-length(prime) is what I have been calling the first n > 0 where 2^n mod prime is 1.
I have inserted some code that calculates this by trial until repetition.. with some trivial uses of it.
long cycleLength(long prime)
{
long remainder = 1 ;
long length = 0 ;
do {
length++ ;
//#define FAST_MODULO
#ifdef FAST_MODULO
remainder = (remainder+remainder)%prime ;
#else
remainder += remainder ;
if (remainder > prime) remainder -= prime ;
#endif
if (remainder == 1)
return length ;
} while (length < prime/2) ;
return prime-1 ;}
size_t pow_of_2(unsigned n)
{
size_t result = 1 ;
size_t pow = 2 ;
while(n)
{
if (n & 1) result *= pow ;
pow *= pow ;
n /= 2;
}
return result ;
}
#include <iostream>
using std::cout ;
int main(int ac, char **av)
{
long prime = 17 ;
cout << "cycleLength(17) = " << cycleLength(17) << '\n';
cout << "2^16 = " << pow_of_2(16) << '\n' ;
cout << "2^33 = " << pow_of_2(33) << '\n' ;
cout << "33 % CL(17) = " << 33 % cycleLength(17)
<< ", 2^(33 % CL(17)) % 17 = " << pow_of_2(33%cycleLength(17)) % 17 << '\n' ;
cout << "2^33 % 17 = " << pow_of_2(33)%17 << '\n' ;
cout << std::endl ;
}
I have observed that cycles are either length (prime-1) or divisor of (prime-1).
So the run-time is reduced by stopping at (n == prime/2) and returning (prime-1) as that is the only case remaining; and the code is about 25% quicker as a result.
The algorithm is currently O(N) time complexity. I am hoping for clues or insight that might reduce this.
Thanks for reading this.