2015-09-09 5 views
2

Как рассчитать (a^b) % c, где 0 <= a, b, c <= 10^18. Здесь (a^b) означает a на питание b, а не a xor b.Вычислить (a^b)% c, где 0 <= a, b, c <= 10^18

Мой текущий код проблемы:

unsigned long long bigMod(unsigned long long b, 
          unsigned long long p, 
          unsigned long long m){ 
    if(b == 1) return b; 
    if(p == 0) return 1; 
    if(p == 1) return b; 

    if(p % 2 == 0){ 
     unsigned long long temp = bigMod(b, p/2ll, m); 
     return ((temp) * (temp))% m; 
    }else return (b * bigMod(b, p-1, m)) % m; 
} 

Для этого входа:

a = 12345 b = 123456789 and c = 123456789

ожидаемый результат должен быть:

59212459031520 
+0

[Экспоненты по квадратуре] (https://en.wikipedia.org/wiki/Exponentiation_by_squaring) может быть полезной отправной точкой. Не сложно добавить модуль в формулу, если вы заметили, что '(a ** b)% c == ((a% c) ** b)% c)'. – Kevin

+0

Возможный дубликат [вычисления a^b mod c] (http://math.stackexchange.com/questions/26722/calculating-ab-mod-c). –

+0

Я пытался ((a% m) * (b% m))% m, но может быть мой подход неправильный. –

ответ

0

Я использую этот код в C++:

long long power(long long a, long long b, long long c) 
{ 
    if (b==0) 
    { 
     return 1; 
    } 

    if (b % 2 == 0) 
    { 
     long long w = power(a, b/2, c); 
     return (w*w) % c; 
    } 
    else 
    { 
     int w = power(a, b-1, c); 
     return (a*w) % c; 
    } 
} 

Он имеет логарифмическую сложность.

+2

не работает, если a и b являются 64 битами, так как 'w * w' нужен 128-битный тип для хранения –

2

У вас возникла проблема с temp * temp (long long overflow). Вы можете опустить эту проблему, используя алгоритм быстрой моды, чтобы умножить их mod m. Здесь Вы рабочий код:

unsigned long long bigMultiply(unsigned long long b,unsigned long long p, unsigned long long m) 
{ 
    if(p == 0)return b; 
    if(p%2 == 0) 
    { 
    unsigned long long temp = bigMultiply(b,p/2ll,m); 
    return ((temp)+(temp))%m; 
    } 
    else 
    return (b + bigMultiply(b,p-1,m))%m; 
}  
unsigned long long bigMod(unsigned long long b,unsigned long long p, unsigned long long m) 
{ 

    if(b == 1) 
    return b; 
    if(p == 0)return 1; 
    if(p == 1)return b; 
    if(p%2 == 0) 
    { 
    unsigned ll temp = bigMod(b,p/2ll,m); 
    return bigMultiply(temp,temp,m); 
    } 
    else 
    return (b * bigMod(b,p-1,m))%m; 
} 
+0

Проблема с некоторыми угловыми случаями:' bigMod (1, p, 1) 'равен 1 и должен быть 0. Предложите' if (b == 1) return b% m ; 'Подобно для' if (p == 0) return 1; '->' if (p == 0) возвращает 1% m; 'для обработки' m == 1' и 'if (p == 1) return b; '- > 'if (p == 1) return b% m;' для обработки 'b> = m'. – chux

+0

Я вполне уверен, что 'b * bigMod (b, p-1, m)' может легко переполняться. В остальном этот код очень хорош, но имеет некоторые ограничения: '(temp) + (temp)' все еще может переполняться, когда 'm> ULLONG_MAX/2', но это находится за пределами' 'c <= 10^18'. – chux

Смежные вопросы