base *= base;
Ваша проблема заключается в этом утверждении, вам вообще не следует изменять base
. Скорее, вам следует регулировать result
на основе постоянного значения base
.
Чтобы выполнить полномочия, вам нужно повторное умножение, но base *= base
дает вам повторное возведение в квадрат значения, и поэтому вы получите гораздо большее значение, чем хотелось бы. Это действительно работает для степеней четырех, поскольку вы выполняете итерацию 4 - 2
раз, возводя каждую итерацию в квадрат, и x4 == (x2)2
.
Это не сработает для более высоких степеней, таких как шесть, поскольку вы выполняете итерацию 6 - 2
раз и x6 != (((x2)2)2)2
. Последнее значение фактически эквивалентно x16
.
Кстати (несмотря на ваше утверждение), на самом деле это не гарантированно работает при степени двойки. Если вы следуете коду в этом случае, вы увидите, что 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-y = 1/xy
);
- неопределенный случай
00
; и
- переполнение, если у вас нет значений произвольной точности (в основном, если
(x * y) / y != x
, вы можете быть достаточно уверены в том, что произошло переполнение). Обратите внимание на использование «не близко к», неразумно проверять точное равенство с плавающей запятой из-за возможности ошибок из-за ограничений точности - гораздо лучше реализовать проверку «достаточно близко к» некоторого описания.
Одна вещь, которую следует иметь в виду при переводе на C или C ++, реализация дополнения 2 вызовет проблемы при использовании самого отрицательного целого числа, поскольку его отрицание часто снова является тем же значением снова из-за дисбаланса между положительными и отрицательными значениями. Это может привести к бесконечной рекурсии.
Вы можете исправить это, просто обнаружив случай на ранней стадии (прежде чем что-либо еще), с помощью чего-то вроде:
if INT_MIN == -INT_MAX - 1 and exp == INT_MIN:
throw bad_input
Первая часть обнаруживает реализацию дополнения до 2, а вторая обнаруживает (проблемное) использование INT_MIN
в качестве показателя степени.
02.02.2020