Привет всем. Продолжаю потихоньку публиковать свои реализации известных всем и очень популярных алгоритмов, например, уже успел реализовать супер сложную быструю сортировку. На этот раз отклонюсь чуть ближе к математике и рассмотрю алгоритм быстрого возведения в степень, который часто(или даже скорее всегда) используется в стандартных библиотечных функциях возведениях.
Но прежде, чем начать, почему бы не реализовать обычное возведение? Правильно, нет причин себе в этом отказывать, поехали!
Функция возведения числа в степень
Методом «в лоб», пробежимся в цикле и перемножим число само на себя сколько нужно раз. Работает за O(deg) где deg степень.
//Возводит число num в степень deg простым циклом
long power(long num, long deg) {
long result = 1;
for(long i = 0; i < deg; i++) {
result *= num;
}
return result;
}
Для возведения по модулю достаточно будет передать этот модуль в функцию и на каждой итерации брать результат по модулю.
Функция возведения числа в отрицательную степень
Небольшое улучшение, добавим возможность возводить число в отрицательную степень. Реализуется легко, изменяем возвращаемое значение и рассматриваем два случая: для положительной степени делаем все как обычно, а для отрицательной возвращаем 1 / result.
//Возводит число num в степень deg простым циклом(степень может быть отрицательной)
double power(long num, long deg) {
double result = 1;
if(deg < 0) {
deg = -deg;
for(long i = 0; i < deg; i++) {
result *= num;
}
return 1 / result;
}
else {
for (long i = 0; i < deg; i++) {
result *= num;
}
return result;
}
}
Функция быстрого возведения числа в степень
Ее еще называют бинарным возведением. Алгоритм построен на очевидной формуле
An = (An/2)2 = An/2 * An/2
То есть для четного n можно получить результат выполнив всего log2n перемножений, что уже дает логарифмическую сложность. А в случае, когда n нечетно, приведем его к четному виду с помощью еще одной очевидной формулы
An = An-1 * An
Реализация выглядит следующим образом.
//Быстрое возведение числа num в степень deg
long powerFast(long num, long deg) {
long result = 1;
while(deg) {
if (deg % 2 == 0) {
deg /= 2;
num *= num;
}
else {
deg--;
result *= num;
}
}
return result;
}
Функция быстрого возведения в отрицательную степень
Можно реализовать воспользовавшись аналогичным приемом, как и в простом умножении — делим алгоритм на две ветки.
//Быстрое возведение числа num в степень deg(в том числе может быть отрицательной)
double powerFast(long num, long deg) {
double result = 1;
if(deg < 0) {
deg = -deg;
while(deg) {
if (deg % 2 == 0) {
deg /= 2;
num *= num;
}
else {
deg--;
result *= num;
}
}
return 1 / result;
}
else {
while(deg) {
if (deg % 2 == 0) {
deg /= 2;
num *= num;
}
else {
deg--;
result *= num;
}
}
return result;
}
}
Заключение
Таким образом мы научились возводить число в степень с логарифмической скоростью, что пригодится для реализации умножения и деления больших чисел(кстати, сложение и вычитание уже готовы). А на сегодня у меня все, спасибо за внимание!