Jaki jest najskuteczniejszy sposób podniesienia liczby całkowitej do potęgi innej liczby całkowitej w C?
// 2^3
pow(2,3) == 8
// 5^5
pow(5,5) == 3125
c
algorithm
math
exponentiation
Doug T.
źródło
źródło
int
s (a nie jakiejś wielkiej klasy), wiele połączeń do ipow przepełni się. Zastanawiam się, czy istnieje sprytny sposób, aby wstępnie obliczyć tabelę i zredukować wszystkie nieprzepełnione kombinacje do prostego wyszukiwania w tabeli. Zajmie to więcej pamięci niż większość ogólnych odpowiedzi, ale być może będzie bardziej wydajne pod względem szybkości.pow()
funkcja nie jest bezpiecznaOdpowiedzi:
Potęgowanie przez kwadrat.
Jest to standardowa metoda wykonywania potęgowania modułowego dla ogromnych liczb w kryptografii asymetrycznej.
źródło
while (exp)
iif (exp & 1)
zwhile (exp != 0)
iif ((exp & 1) != 0)
odpowiednio.unsigned exp
, lub inaczejexp
poprawnie obsługiwać negację .n*n*n*n*n*n*n*n
wykorzystuje 7 mnożenia. Ten algorytm zamiast tego obliczam=n*n
, ao=m*m
następniep=o*o
, gdziep
= n ^ 8, tylko z trzema multiplikacjami. W przypadku dużych wykładników różnica w wydajności jest znacząca.Zauważ, że potęgowanie przez kwadrat nie jest najbardziej optymalną metodą. Jest to prawdopodobnie najlepsza metoda, jaką można zrobić jako ogólną metodę, która działa dla wszystkich wartości wykładniczych, ale dla konkretnej wartości wykładniczej może istnieć lepsza sekwencja, która wymaga mniejszej liczby mnożenia.
Na przykład, jeśli chcesz obliczyć x ^ 15, metoda potęgowania przez podniesienie do kwadratu da ci:
Jest to w sumie 6 multiplikacji.
Okazuje się, że można tego dokonać za pomocą „tylko” 5 krotności poprzez potęgowanie łańcucha dodatków .
Nie ma wydajnych algorytmów pozwalających znaleźć tę optymalną sekwencję mnożenia. Z Wikipedii :
źródło
Jeśli musisz podnieść 2 do potęgi. Najszybszym sposobem na to jest przesunięcie bitowe według siły.
źródło
2 ** 0 == 1 << 0 == 1
Oto metoda w Javie
źródło
źródło
pow(1, -1)
nie opuszcza zakresu int pomimo ujemnego wykładnika. Teraz, gdy ktoś działa przez przypadek, tak jak działapow(-1, -1)
.Jeśli chcesz uzyskać wartość liczby całkowitej dla 2 podniesioną do potęgi czegoś, zawsze lepiej jest użyć opcji shift:
pow(2,5)
można zastąpić1<<5
Jest to o wiele bardziej wydajne.
źródło
power()
funkcja działa tylko dla liczb całkowitychZłożoność = O (log (exp))
power()
funkcja do pracy dla ujemnego exp i float base .Złożoność = O (log (exp))
źródło
float
drugiego przedstawionego bloku kodu (rozważ pokazanie, w jaki sposóbpower(2.0, -3)
zostanie obliczony).negative exp and float base
rozwiązanie? dlaczego używamy temp, oddziel exp przez 2 i sprawdzamy exp (parzyste / nieparzyste)? dzięki!Niezwykle wyspecjalizowanym przypadkiem jest, gdy trzeba powiedzieć 2 ^ (- x do y), gdzie x jest oczywiście ujemne, a y jest zbyt duże, aby wykonać przesunięcie int. Nadal możesz zrobić 2 ^ x w stałym czasie, wkręcając pływak.
Możesz uzyskać więcej mocy 2, używając podwójnego jako typu podstawowego. (Wielkie dzięki dla komentujących za pomoc w poprawieniu tego posta).
Istnieje również możliwość, że jeśli dowiesz się więcej o pływakach IEEE , mogą pojawić się inne specjalne przypadki potęgowania.
źródło
Podobnie jak kontynuacja komentarzy na temat wydajności potęgowania przez kwadrat.
Zaletą tego podejścia jest to, że działa w czasie log (n). Na przykład, jeśli zamierzasz obliczyć coś wielkiego, na przykład x ^ 1048575 (2 ^ 20-1), musisz przejść przez pętlę tylko 20 razy, a nie 1 milion +, stosując podejście naiwne.
Również pod względem złożoności kodu jest prostsze niż próba znalezienia najbardziej optymalnej sekwencji multiplikacji, co sugeruje la Pramod.
Edytować:
Chyba powinienem wyjaśnić, zanim ktoś oznaczy mnie tagiem pod kątem możliwości przepełnienia. Podejście to zakłada, że masz jakąś ogromną bibliotekę.
źródło
Późno na imprezę:
Poniżej znajduje się rozwiązanie, które radzi sobie
y < 0
najlepiej, jak to możliwe.intmax_t
dla maksymalnego zasięgu. Nie ma przepisów dotyczących odpowiedzi, które nie pasująintmax_t
.powjii(0, 0) --> 1
co jest częstym wynikiem w tym przypadku.pow(0,negative)
, zwraca kolejny niezdefiniowany wynikINTMAX_MAX
Ten kod używa pętli
for(;;)
na zawsze, aby uniknąć ostatecznegobase *= base
wspólnego w innych zapętlonych rozwiązaniach. To zwielokrotnienie jest 1) niepotrzebne i 2) może byćint*int
przepełnieniem, które jest UB.źródło
powjii(INT_MAX, 63)
powoduje UB wbase *= base
. Zastanów się, czy możesz pomnożyć lub przejść do niepodpisanego i pozwolić mu się zawijać.exp
podpisania. To komplikuje kod z powodu nieparzystej sytuacji, w której(-1) ** (-N)
jest poprawny, i każdaabs(base) > 1
będzie miała0
ujemne wartościexp
, więc lepiej mieć go bez znaku i zapisać ten kod.y
podpisany nie jest tak naprawdę potrzebny i powoduje komplikacje, które skomentowałeś, ale prośba OP była konkretnapow(int, int)
. Tak więc te dobre komentarze należą do pytania OP. Ponieważ OP nie określił, co robić w przypadku przepełnienia, dobrze zdefiniowana zła odpowiedź jest tylko nieznacznie lepsza niż UB. Biorąc pod uwagę „najbardziej efektywny sposób”, wątpię, by OP troszczył się o OF.bardziej ogólne rozwiązanie z uwzględnieniem ujemnego exponenetu
źródło
pow(i, INT_MIN)
może być nieskończoną pętlą.pow(i, INT_MIN)
nie jest przepełnieniem liczb całkowitych. Przypisanie tego wyniku do ztemp
pewnością może się przelać, potencjalnie powodując koniec czasu , ale zadowolę się pozornie losową wartością. :-)Jeszcze jedna implementacja (w Javie). Może nie być najskuteczniejszym rozwiązaniem, ale liczba iteracji jest taka sama jak w przypadku rozwiązania wykładniczego.
źródło
Używam rekurencyjnego, jeśli exp jest parzysty, 5 ^ 10 = 25 ^ 5.
źródło
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:
Uwagi dotyczące tej funkcji:
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żywaniaint
) lub coś podobnego, który powinien zostać zoptymalizowany, ale jest brzydsze, a nie wyrazem C stała. Również rzutowanie wynikusqrt()
na „int
nie” jest bardzo dobre z powodu precyzji zmiennoprzecinkowej w przypadku idealnego kwadratu, ale ponieważ nie znam żadnej implementacji, w którejINT_MAX
- lub maksimum dowolnego typu - jest idealnym kwadratem, możesz żyć z tym.źródło
Wdrożyłem algorytm, który zapamiętuje wszystkie obliczone moce, a następnie wykorzystuje je w razie potrzeby. Na przykład x ^ 13 jest równe (x ^ 2) ^ 2 ^ 2 * x ^ 2 ^ 2 * x gdzie x ^ 2 ^ 2 wziął z tabeli zamiast go ponownie obliczać. Jest to w zasadzie implementacja odpowiedzi @Pramod (ale w języku C #). Wymagana liczba mnożenia to Ceil (Log n)
źródło
public
? 2 funkcje o tej samej nazwie? To jest pytanie C.Mój przypadek jest trochę inny, próbuję stworzyć maskę z mocy, ale pomyślałem, że i tak podzielę się rozwiązaniem, które znalazłem.
Oczywiście działa tylko dla potęg 2.
źródło
#define MASK(e) (((e) >= 64) ? -1 :( (1 << (e)) - 1))
, aby można je było obliczyć w czasie kompilacjiJeśli znasz wykładnik (i jest to liczba całkowita) w czasie kompilacji, możesz użyć szablonów do rozwinięcia pętli. Można to uczynić bardziej wydajnym, ale chciałem tutaj przedstawić podstawową zasadę:
Kończymy rekurencję za pomocą specjalizacji szablonu:
Wykładnik musi być znany w czasie wykonywania,
źródło
(c != c++) == 1