Привет всем. Продолжаю потихоньку публиковать свои реализации известных всем и очень популярных алгоритмов, например, уже успел реализовать супер сложную быструю сортировку. На этот раз отклонюсь чуть ближе к математике и рассмотрю алгоритм быстрого возведения в степень, который часто(или даже скорее всегда) используется в стандартных библиотечных функциях возведениях.
Но прежде, чем начать, почему бы не реализовать обычное возведение? Правильно, нет причин себе в этом отказывать, поехали!
Функция возведения числа в степень
Методом «в лоб», пробежимся в цикле и перемножим число само на себя сколько нужно раз. Работает за 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; } }
Заключение
Таким образом мы научились возводить число в степень с логарифмической скоростью, что пригодится для реализации умножения и деления больших чисел(кстати, сложение и вычитание уже готовы). А на сегодня у меня все, спасибо за внимание!