Чтобы сделать это реальным ответом на C ++ - это та задача, в которой вы могли бы подумать о том, чтобы сделать ее функцией шаблона, поскольку она должна работать с любым типом чисел.
Рекурсия на самом деле является хорошей идеей, но только если вы используете преимущества, которые она может предложить: она может избежать некоторых умножений, вычтя низкие числа из показателя степени.
template <typename NumT>
NumT raiseTo(NumT base, unsigned exponent) {
if (exponent == 1) return base;
if (exponent == 0) return 1;
if (exponent%2 == 0) { NumT ressqrt = raiseTo(base,exponent/2)
; return ressqrt*ressqrt; }
if (exponent%3 == 0) { NumT rescubrt = raiseTo(base,exponent/3)
; return rescubrt*rescubrt*rescubrt; }
else return base * raiseTo(base, --exponent);
}
Пример того, сколько вычислений можно сэкономить: предположим, что вы хотите поднять число до 19. Это 18 умножений, если вы используете наивный циклоподобный подход. При таком решении получается
- 19 не делится ни на 2, ни на 3, поэтому рассчитайте b ⋅ b e -1 , то есть
- б 18 . Теперь 18 делится на 2, поэтому мы возводим в квадрат b e / 2 , что составляет
- б 9 . Где 9 делится на 3, поэтому мы куб b e / 3 , что составляет
- б 3 . Где 3 делится на 3, поэтому мы куб b e / 3 , что составляет
- b 1 , то есть b.
Это было только 1 + 1 + 2 + 2 = 6 умножений, 1/3 от необходимой суммы для циклического подхода! Однако обратите внимание, что это не обязательно означает, что код будет выполняться гораздо быстрее, поскольку проверка факторов также занимает некоторое время. В частности, %3
на unsigned
с, вероятно, не быстрее, чем умножение на int
с, поэтому для NumT==int
это не совсем умно. Но он является умным для более дорогих типов с плавающей запятой, complex
, не говоря уже о типах матриц линейной алгебры, для которых умножение может быть чрезвычайно дорогим.