Oprócz odpowiedzi Eliasa, która powoduje niezdefiniowane zachowanie po zaimplementowaniu za pomocą liczb całkowitych ze znakiem, oraz niepoprawne wartości wysokich danych wejściowych po zaimplementowaniu za pomocą liczb całkowitych bez znaku,
tutaj jest zmodyfikowana wersja potęgowania przez kwadrat, która działa również z podpisanymi typami liczb całkowitych i nie podaje niepoprawnych wartości:
#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;
}
Uwagi dotyczące tej funkcji:
(1 ** N) == 1
(N ** 0) == 1
(0 ** 0) == 1
(0 ** N) == 0
Jeśli nastąpi przelew lub owijanie, return 0;
Użyłem int64_t
, ale dowolnej szerokości (podpisanej lub niepodpisanej) można używać z niewielką modyfikacją. Jednakże, jeśli chcesz używać bez stałej szerokości typu INTEGER, będzie trzeba zmienić SQRT_INT64_MAX
przez (int)sqrt(INT_MAX)
(w przypadku używania int
) lub coś podobnego, który powinien zostać zoptymalizowany, ale jest brzydsze, a nie wyrazem C stała. Również rzutowanie wyniku sqrt()
na „ int
nie” jest bardzo dobre z powodu precyzji zmiennoprzecinkowej w przypadku idealnego kwadratu, ale ponieważ nie znam żadnej implementacji, w której INT_MAX
- lub maksimum dowolnego typu - jest idealnym kwadratem, możesz żyć z tym.