base *= base;
Ваша проблема заключается в этом утверждении, вы не должны менять base
вообще. Скорее, вы должны корректировать result
на основе константного значения base
.
Чтобы сделать полномочия, вам нужно повторить умножение, , но base *= base
дает вам повторное квадрат от значения, и поэтому вы получите намного большее значение, чем нужно. Это на самом деле работает для степеней четырех, так как вы повторяете 4 - 2
раз, возводя в квадрат каждую итерацию, и x<sup>4</sup> == (x<sup>2</sup>)<sup>2</sup>
.
Это будет не работать для более высоких степеней, как шесть, поскольку вы повторяете 6 - 2
раз и x<sup>6</sup> != (((x<sup>2</sup>)<sup>2</sup>)<sup>2</sup>)<sup>2</sup>
. Это последнее значение на самом деле эквивалентно x<sup>16</sup>
.
В качестве отступления (несмотря на ваше утверждение) на самом деле не гарантированно работает для двух степеней. Если вы будете следовать коду в этом случае, вы увидите, что result
никогда не присваивается значение, поэтому возвращаемое значение будет произвольным. Если это работает для вас, это случайно и может в какой-то момент вас укусить.
Алгоритм, который вы можете использовать, должен выглядеть примерно так:
float power(float base, int exponent):
# 0^0 is undefined.
if base == 0 and exponent == 0:
throw bad_input
# Handle negative exponents.
if exponent < 0:
return 1 / power(base, -exponent)
# Repeated multiplication to get power.
float result = 1
while exponent > 0:
# Use checks to detect overflow.
float oldResult = result
result *= base
if result / base is not close to oldResult:
throw overflow
exponent -= 1
return result
Этот алгоритм обрабатывает:
- отрицательные целочисленные показатели (начиная с
x<sup>-y</sup> = <sup>1</sup>/<sub>x<sup>y</sup></sub>
); - неопределенный регистр
0<sup>0</sup>
; и - переполнение, если у вас нет значений произвольной точности (в основном, если
(x * y) / y != x
, вы можете быть достаточно уверены, что произошло переполнение). Обратите внимание на использование «не близко к», неразумно проверять поплавки на точное равенство из-за вероятности ошибок из-за пределов точности - гораздо лучше реализовать проверку «достаточно близко к» некоторого описания.
Одна вещь, о которой следует помнить при переводе на C или C ++, реализация дополнения 2 вызовет проблемы при использовании наиболее отрицательного целого числа, так как его отрицание часто снова становится тем же значением из-за дисбаланса между положительные и отрицательные значения. Это может привести к бесконечной рекурсии.
Это можно исправить, просто обнаружив случай на раннем этапе (прежде всего), например:
if INT_MIN == -INT_MAX - 1 and exp == INT_MIN:
throw bad_input
Первая часть этого обнаруживает реализацию дополнения 2, а вторая обнаруживает (проблематично c) использование INT_MIN
в качестве показателя степени.