В дополнение к ответу Элиаса, который приводит к неопределенному поведению при реализации с целыми числами со знаком и к неправильным значениям для высокого ввода при реализации с целыми числами без знака,
Вот модифицированная версия Exponentiation by Squaring, которая также работает со знаковыми целочисленными типами и не дает неправильных значений:
#include <stdint.h>
#define SQRT_INT64_MAX (INT64_C(0xB504F333))
int64_t alx_pow_s64 (int64_t base, uint8_t exp)
{
int_fast64_t base_;
int_fast64_t result;
base_ = base;
if (base_ == 1)
return 1;
if (!exp)
return 1;
if (!base_)
return 0;
result = 1;
if (exp & 1)
result *= base_;
exp >>= 1;
while (exp) {
if (base_ > SQRT_INT64_MAX)
return 0;
base_ *= base_;
if (exp & 1)
result *= base_;
exp >>= 1;
}
return result;
}
Соображения для этой функции:
(1 ** N) == 1
(N ** 0) == 1
(0 ** 0) == 1
(0 ** N) == 0
Если произойдет какое-либо переполнение или упаковка, return 0;
Я использовал int64_t
, но любая ширина (со знаком или без знака) может быть использована с небольшими изменениями. Однако, если вам необходимо использовать не фиксированную ширину целочисленного типа, то нужно изменить SQRT_INT64_MAX
путь (int)sqrt(INT_MAX)
(в случае использования int
) или нечто подобное, которые должны быть оптимизированы, но это уродливее, а не выражение константы С. Кроме того, приведение результата sqrt()
к an int
не очень хорошо из-за точности с плавающей запятой в случае идеального квадрата, но поскольку я не знаю ни одной реализации, где INT_MAX
- или максимум любого типа - является идеальным квадратом, вы можете жить с этим.