2010-10-12 10 views
5

Potrzebuję bitowego narzędzia liczącego w C++, które jest w stanie zliczyć numer najbardziej znaczącego bitu w stałej liczbowej i przedstawić tę liczbę jako stałą czasu kompilacji.Metaprogram do zliczania bitów

Wystarczy, aby wszystko jasne - numer najbardziej znaczącego bitu do zbioru wartości liczbowych:

255 => 8 (11111111b) 
    7 => 3 (111b) 
1024 => 11 (10000000000b) 
    26 => 5 (11010b) 

jestem nowy w programowaniu szablonu, ale myślę, że jest droga.

Proszę podać kilka próbek kodu, każda pomoc będzie doceniona.

+1

Innymi słowy, trzeba 'piętro (lg (n)) + 1 ', gdzie' lg' jest podstawa 2 logarytm. – outis

+1

Jaka byłaby poprawna wartość dla 0? –

+0

Tak, potrzebuję dokładnie 'podłogi (lg (n)) + 1'. '0' oznacza, że ​​bity nie są wymagane do zapisania tego numeru, więc wynik również wynosi 0. – Keynslug

Odpowiedz

12

Edytuj: Całkowicie błędnie przeczytałem, co chciałeś.

Oto co chcesz:

liczba znaczących bitów w 0 0.

liczba znaczących bitów w x jest liczba znaczących bitów w x/2 plus jeden.

Więc dostaniesz:

template <unsigned int x> 
struct SignificantBits { 
    static const unsigned int n = SignificantBits<x/2>::n + 1; 
}; 

template <> 
struct SignificantBits<0> { 
    static const unsigned int n = 0; 
}; 
+0

C++ zawsze ma dla mnie głębsze głębie. Niesamowite. –

+0

OK! świetne rozwiązanie, ale zakładam, że powinienem trochę edytować pytanie. – Keynslug

+2

Ten szablon podaje liczbę bitów '1', ale nie minimalną liczbę bitów potrzebną do zapisania wartości. W tym celu należy zamienić '(x% 2)' na '1'. –

1

Oto moja implementacja; mniej elegancki niż @ sepp2k, stosuje inne podejście, faktycznie licząc bity i zapewniając zarówno pozycję MSB, jak i liczbę znaczących bitów.

#include <iostream> 
#include <limits> 

// Number: the number to be examined; Bit: parameter used internally to specify the bit to 
// examine (the work starts from the leftmost bit) 
template<unsigned int Number, unsigned int Bit=std::numeric_limits<unsigned int>::digits-1> 
class BitCounter 
{ 
public: 
    // Most Significant Bit number; if it's the current, fine, otherwise 
    // delegate the work to another template that will examine the next bit 
    static const int MSB=(Number&(1<<Bit))?Bit:BitCounter<Number,Bit-1>::MSB; 
    // Count of significant bits - actually, MSB+1 
    static const int Count=MSB+1; 
}; 

// Corner case: we reached the first bit 
template<unsigned int Number> 
class BitCounter<Number,0> 
{ 
public: 
    // If it's 1, the MSB is the bit 0 (the rightmost), while if it's 0 it's "one before"; 
    // this is somewhat arbitrary to make Count get 0 for 0 and 1 for 1, you may want to 
    // change it just to 0 
    static const int MSB=Number==0?-1:0; 
    static const int Count=MSB+1; 
}; 

int main() 
{ 
    std::cout<<BitCounter<255>::Count<<" " 
      <<BitCounter<7>::Count<<" " 
      <<BitCounter<1024>::Count<<" " 
      <<BitCounter<26>::Count<<" " 
      <<BitCounter<1>::Count<<" " 
      <<BitCounter<0>::Count<<std::endl; 
    return 0; 
} 

Przykładowe wyjście:

[email protected]:~/cpp$ g++ tpl_bitcount.cpp -Wall -Wextra -ansi -pedantic -O3 -o tpl_bitcount.x && ./tpl_bitcount.x 
8 3 11 5 1 0