|
Поскольку в нашем распоряжении только
операция умножения, то следует организовать циклический
процесс умножений.
Очевидный вариант: на каждом шаге
цикла умножений участвуют два сомножителя - значение "уже
сосчитанного произведения" и "оставшееся", содержащее
показатель степени. Показатель степени второго сомножителя
уменьшается на 1, а первый сомножитель, соответственно,
умножается на основание степени. Ясно, что начав со значения 1
для первого сомножителя, цикл потребует число шагов, равное
значению показателя степени m.
Хотелось бы уменьшить количество умножений.
Это удается, если воспользоваться следующим свойством операции
возведения в степень:
Следуя ему, получаем улучшенный
вариант: будем на каждом шаге до "обнуления" показателя
степени
-
при нечетном значении показателя степени
второго сомножителя - домножать первый сомножитель на
значение основания степени второго сомножителя; уменьшать на
1 и затем делить пополам сам показатель;
-
при четном значении - возводить во вторую
степень основание второго сомножителя, уменьшая при этом
вдвое показатель степени.
Проиллюстрируем механизм предлагаемого
алгоритма на примере. Пусть в качестве показателя степени
предложено значение m=15.
Описанный механизм называется
дихотомическим алгоритмом возведения в степень.
(Заметим, кстати, что с применением дихотомии, то есть деления
пополам, нам еще не однажды придется встретиться в других
алгоритмах.)
С точки зрения двоичной арифметики, идея
особенно плодотворна, поскольку возведение в степень 2 легко
реализуется сдвигом аргумента на один бит влево, а деление на
2 - сдвигом вправо. Теперь несложно написать соответствующую
процедуру.
function Power (a, m : byte) : longint;
var
_a : longint; {текущее значение основания степени}
_m : byte; {текущее значение показателя степени}
p : longint; {текущее значение накопленного
произведения}
begin
if m = 0 then
begin
Power := 1;
Exit
end;
p := 1;
_a := a;
_m := m;
while _m > 0 do
begin
if _m and 1 = 1 then p := p * _a;
_a := _a * _a;
_m := _m shr 1;
end;
Power := p
end;
Этот вариант функции вычисляет значение
степени только для неотрицательных значениях аргументов. Более
широкий диапазон входных значений позволит обрабатывать
функция, написать которую предлагает
|