2013-03-20 14 views
6

mam wymóg obliczenia k jak najmniejszej mocy 2, który jest> = liczba całkowita, n (n jest zawsze> 0)Skuteczna obliczanie mocy 2

obecnie ja z:

#define log2(x) log(x)/log(2) 
#define round(x) (int)(x+0.5) 

k = round(pow(2,(ceil(log2(n))))); 

to w wydajności krytycznej funkcji

Czy jest bardziej efektywny obliczeniowo sposób obliczania k?

+3

Jeśli używasz GCC, możesz użyć '1 << CHAR_BIT * sizeof x - __builtin_clz (x)', pod warunkiem, że 'x' ma typ' unsigned int' lub, w normalnych systemach, 'int'. Istnieje również "__builtin_clzl" dla 'unsigned long'. Niektóre kompilatory bez GCC również obsługują to rozszerzenie. To będzie szybsze niż jakakolwiek inna dotychczasowa odpowiedź na procesory, które mają instrukcję "znajdź pierwszy bit set". –

+0

edytowanie notatek z "> wartości całkowitej" na "> = wartość całkowita" – bph

+1

Teraz wszyscy muszą ponownie zmienić swoje odpowiedzi. :-) –

Odpowiedz

2
int calculate_least_covering_power_of_two(int x) 
{ 
    int k = 1; 
    while(k < x) k = k << 1; 
    return k; 
} 
+0

dziękuję za ostatnią edycję, odpowiedź jest teraz poprawna – bph

+1

porównuje to z wersją bez gałęzi, podejrzewam, że przekonasz się, że nie jest to najskuteczniejszy sposób na zrobienie tego. Ale to zadziała. –

+0

@RandyHoward Zrobiłem to i tam nie ma zauważalnych różnic (dla mojej aplikacji), więc myślę, że pozostanę z tą odpowiedzią jako prostszą, – bph

1
k = 1 << (int)(ceil(log2(n))); 

Można skorzystać z faktu, że cyfry binarne reprezentują moce dwóch (1 to 1, 10 2, 100 wynosi 4, etc). Przesunięcie 1 o wykładnik 2 daje tę samą wartość, ale jest znacznie szybsze.

Chociaż jeśli uda Ci się jakoś ominąć sufit (log2 (n)), zobaczysz znacznie większy wzrost wydajności.

+0

Ten kod nie kompiluje się, ponieważ 'ceil' ma typ 'double' i nie można go używać z' << '. Kiedy wstawiono rzut do 'int' i' n' wynosi 32, kod ten daje 32, ale pożądany wynik to 64. –

+0

Dodałem rzut do int do przykładu. Nie jestem pewien, dlaczego pożądanym rezultatem dla n = 32 byłoby 64 ... może nie zrozumiałem pierwotnego pytania. – Zach

+1

@EricPostpischil, wygląda na to, że prosi o najmniejszą potęgę 2 większą lub równą n. 32 jest równe 32. Ale może nadal nie rozumiem. Tak czy inaczej, odpowiedź Randy'ego Howarda jest lepsza. – Zach

9
/* returns greatest power of 2 less than or equal to x, branch-free */ 
/* Source: Hacker's Delight, First Edition. */ 
int 
flp2(int x) 
{ 
    x = x | (x>>1); 
    x = x | (x>>2); 
    x = x | (x>>4); 
    x = x | (x>>8); 
    x = x | (x>>16); 
    return x - (x>>1); 
} 

To zabawne, aby go zbadać i zobaczyć, jak działa. Myślę, że jedyny sposób, abyś wiedział na pewno, które z rozwiązań, które widzisz, będą optymalne dla twojej sytuacji, to wykorzystać je wszystkie w opcjach tekstowych i profilować je i zobaczyć, które jest najbardziej efektywne dla twojego celu.

Będąc bez gałęzi, ten prawdopodobnie będzie dość dobry pod względem wydajności w stosunku do niektórych innych, ale powinieneś przetestować go bezpośrednio, aby mieć pewność.

Jeśli chcesz najmniejszą moc dwóch większą lub równą X, można użyć nieco inne rozwiązanie:

unsigned 
clp2(unsigned x) 
{ 
    x = x -1; 
    x = x | (x >> 1); 
    x = x | (x >> 2); 
    x = x | (x >> 4); 
    x = x | (x >> 8); 
    x = x | (x >> 16); 
    return x + 1; 
} 
+0

To jest miłe, ponieważ "left left" 1 jest odpowiedzią, że celem jest 0 wszystkich innych bitów, robi to ładnie. Będziesz potrzebował dodatkowej linii dla liczb 64-bitowych. –

+0

Ach tak, chciałeś czegoś innego, pozwól mi to opublikować. –

+0

Jeśli używasz 'x | = x >> 1; ... "formularz, możesz pozbyć się nawiasów, ponieważ operatory przypisania mają bardzo niski priorytet. – wildplasser

2
lim = 123; 
n = 1; 
while((n = n << 1) <= lim); 

pomnożyć liczbę przez 2 aż będzie większy niż Lim.

Lewy przesunięcie jednej wartości mnoży przez 2.

+0

@EricPostpischil Tnx dla zauważenia, naprawiono ... (nie działa dla lim = zero, ale można to rozwiązać za pomocą if()) –

2

Tak, można obliczyć biorąc to po prostu numer, o którym mowa, i używając-bitowych przesunięcia, aby określić moc 2.
prawym przesunięcia bierze wszystko bity liczby i przesuwają je w prawo, upuszczając cyfrę skrajnie prawą (najmniej znaczącą). Jest to równoważne wykonywaniu dzielenia całkowitoliczbowego przez 2. Przesunięcie w prawo wartości przenosi wszystkie bity w lewo, upuszczając bity, które przesuwają się z lewego końca, i dodając zera do prawego końca, skutecznie pomnażając wartość przez 2. Jeśli więc policzycie, ile razy trzeba przesunąć w prawo, zanim liczba osiągnie zero, obliczono całkowitą część logarytmu podstawowego 2. Następnie użyj go, aby utworzyć wynik, przesuwając wielokrotnie wartość 1 wiele razy.

int CalculateK(int val) 
    { 
     int cnt = 0; 
     while(val > 0) 
     { 
      cnt++; 
      val = val >> 1; 
     } 
     return 1 << cnt; 
    } 

EDIT: Ewentualnie, i nieco prostsze: nie trzeba obliczyć Hrabia

int CalculateK(int val) 
    { 
     int res = 1; 
     while(res <= val) res <<= 1; 
     return res ; 
    } 
+0

ahhh, następnie +1 to błąd, który go usunąłem –

+0

Tak, dziękuję Eric! –

1

Źródło: hackersdelight.org

/* altered to: power of 2 which is greater than an integer value */ 

unsigned clp2(unsigned x) { 
    x = x | (x >> 1); 
    x = x | (x >> 2); 
    x = x | (x >> 4); 
    x = x | (x >> 8); 
    x = x | (x >>16); 
    return x + 1; 
} 

Należy pamiętać trzeba będzie dodać:

x = x | (x >> 32); 

Dla liczb 64-bitowych.