-4

I've tried big mod algorithm successfully with numbers like 9^(10^9). But when the power is also too much big to use, how to get the final answer?

#include <iostream>
#include <cmath>
#define ULL unsigned long long
using namespace std;

ULL mod(ULL b, ULL p,ULL m)
{
    ULL md=1,c;
    while(p!=0)
{
    if (p % 2 == 0)
    {
        md*=(b%m)*(b%m);
        p=p/2;
    }
    else 
    {
        md*=(b % m);
        p--;
    }
}
    return md;
}

int main()
{
ULL b=4, p, m=pow(9,9), num,res;
cin >> p;
num= mod(b,p,m);
res=pow(num,4);
cout << res;
}
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Samnan Rahee
  • 31
  • 1
  • 7
  • There is no `x^4` here, and be careful with modular powers: the exponent is not taken modulo the same number as the whole thing – harold Jun 09 '17 at 20:14
  • Are you asking about what you should do if `p` does not fit in `unsigned long long`? Or you need to calculate exactly that number in the topic? – DAle Jun 09 '17 at 20:18
  • Yes I'm asking about what to do if p doesn't fit unsigned long long @DAle – Samnan Rahee Jun 09 '17 at 20:35
  • @SamnanRahee, use long arithmetics library, https://en.wikipedia.org/wiki/List_of_C%2B%2B_multiple_precision_arithmetic_libraries or you can implement it by yourself. By the way, your `mod` function is not completely correct. – DAle Jun 09 '17 at 20:39
  • where's the mistake? :( @DAle – Samnan Rahee Jun 09 '17 at 20:44
  • @SamnanRahee, it seems that it contains too many mistakes. Take a look at sample implementation here: http://en.wikipedia.org/wiki/Modular_exponentiation – DAle Jun 09 '17 at 20:56
  • There is a discrepancy between title&code (`9^9`) and the body (`9^(10^9)`) of this question. – greybeard Jan 27 '19 at 12:26

1 Answers1

1

Consider the general case for calculating (4^(p))%(9^9), where p is a large number (in this case p = 4^(10^9)). Consider the sequence of powers of 4 modulo 9^9: (4^0)%(9^9) == 1, (4^1)%(9^9) == 4, (4^2)%(9^9) == 16, eventually after t (t is unknown) cycles, the sequence will cycle back to (4^t)%(9^9) == 1, after which it repeats. (Note the numbers have to be "coprime", otherwise after some number of cycles, the result becomes zero and remains zero.) So the calculation can use p%t instead of p:

(4^(p))%(9^9) == (4^(p%t))%(9^9)

This seems large, but t will be <= 9^9, and 9^9 is < 2^29, and 4 * 2^29 = 2^31, so 64 bit integers (needed for squaring to speed up exponentiation) will large enough to solve this. So the issue now is to solve for t. You could determine t by starting with | m = 1 | t = 0 | and then looping with | m = (m*4)%(9^9) | t += 1 | until m == 1 again.

For example, say you were looking for t such that:

(4^(p))%9 == (4^(p%t))%9

For this simpler example:

(4^0)%9 == 1      ;m == 1, t == 0
(4^1)%9 == 4      ;m == 4, t == 1
(4^2)%9 == 7      ;m == 7, t == 2
(4^3)%9 == 1      ;m == 1, t == 3   (end of loop)

so t == 3 (for this simpler case):

(4^(p))%9 == (4^(p%3))%9

As commented by DAle, there's also the Euler theorem related to totient:

https://en.wikipedia.org/wiki/Euler%27s_totient_function#Euler.27s_theorem

If a and n are coprime, then

(a^(ϕ(n)))%n = 1, where ϕ(n) is the totient function.

The wiki article also includes a formula for the totient function.

https://en.wikipedia.org/wiki/Euler%27s_totient_function#Euler.27s_product_formula

You could use t = ϕ(9^9). This won't be the smallest value for t that will satisfy (4^(t))%(9^9) = 1, but it will be good enough.


it's been two days since the question was posted, so continuing

t = ϕ(9^9) = ϕ(3^18) = (3^18)(1-1/3) = 2(3^17) = 258280326

Using the loop method finds a smaller value, t = 3^17 = 129140163. This is then used for the inner power modulo

p%t = ( (4^(10^9)) % 129140163 ) = 19457986

Then continuing the process for the outer power modulo

(4^(4^(10^9)))%(9%9) = (4^19457986)%(9^9) = 335228719

Example code:

#include <stdio.h>

typedef unsigned long long uint64_t;

/* count number of cycles t such that */
/* (v^t)%m = 1 */
uint64_t cntcyc(uint64_t v, uint64_t m)
{
uint64_t t = 0;
uint64_t i = 1;
    do {
        i = (i * v) % m;
        t++;
    } while (i != 1);
    return t;
}

/* v to power p modulo m */
uint64_t powmod(uint64_t v, uint64_t p, uint64_t m)
{
uint64_t s = v;                         /* repeated square */
uint64_t r = 1;                             /* result */
    while(p){
        if(p&1)
            r = (r*s)%m;
        s = (s*s)%m;
        p >>= 1;
    }
    return r;
}

int main()
{
uint64_t r;
    r = cntcyc(4ull, 387420489ull);      /* 4, 9^9 */
    printf("%llu\n", r);                 /*   129140163 */
    r = powmod(4ull, 1000000000ull, r);  /* (4^(10^9))%r */
    printf("%llu\n", r);                 /*   19457986 */
    r = powmod(4ull, r, 387420489ull);   /* (4^r)%(9^9) */
    printf("%llu\n", r);                 /*   335228719 */
    r = 258280326ull;                    /* r = totient(9^9) */
    r = powmod(4ull, 1000000000ull, r);  /* (4^(10^9))%r */
    printf("%llu\n", r);                 /*   19457986 */
    r = powmod(4ull, r, 387420489ull);   /* (4^r)%(9^9) */
    printf("%llu\n", r);                 /*   335228719 */
    r = 258280326ull;                    /* r = totient(9^9) */
    r = powmod(4ull, 1000000000ull, r);  /* (4^(10^9))%r */
    /* show that r += 3^17 doesn't effect final result */
    r += 129140163ull;                   /* r += 3^17 */
    printf("%llu\n", r);                 /*   148598149 */
    r = powmod(4ull, r, 387420489ull);   /* (4^r)%(9^9) */
    printf("%llu\n", r);                 /*   335228719 */
    return 0;
}
rcgldr
  • 27,407
  • 3
  • 36
  • 61
  • The last answer that you gave was exactly what I was looking for @rcgldr thanks a lot. and sorry for my inconvenience, I couldn't log in to Stacksoverflow as I was kinda busy lately. – Samnan Rahee Jun 16 '17 at 05:55