2012-06-08 8 views
9

Muszę jak najszybciej przekonwertować liczbę binarną, na przykład unsigned int bin_number = 10101010 na jej dziesiętną reprezentację (tj. 170)? Jaki jest najlepszy algorytm?Szybki sposób konwertowania liczby binarnej na liczbę dziesiętną

+1

Czy '10101010' pochodzi od użytkownika twojego programu, czy jest to tylko literał w kodzie? –

+0

Czy możesz podać lepszy obraz skąd pochodzi liczba binarna? Czy jest znany podczas kompilacji lub tylko w czasie wykonywania? Czy jest przechowywany w ciągu znaków lub w innej strukturze? Znajomość tego znacznie ułatwi udzielenie odpowiedzi na to pytanie. –

+0

Tak, przepraszam. Zazwyczaj uzyskuję liczbę uruchomień, ale czasami podczas kompilacji. Nadal się uczę. – Nick

Odpowiedz

10

Za pomocą szablonów można rozwiązać ten problem pod numerem podczas kompilacji.

template<unsigned long num> 
struct binary 
{ 
    static unsigned const value = 
     binary<num/10>::value << 1 | num % 10; 
}; 

// Specialization for zero 
template<> 
struct binary<0> 
{ static unsigned const value = 0; }; 

Szablon binarny jest ponownie tworzony z mniejszą num, aż num osiągnie zero, a specjalizacja jest stosowany jako warunek zakończenia.

Przykład: std::cout << binary<10101010>::value;

Dla run-time Problem:

unsigned binary_to_decimal(unsigned num) 
{ 
    unsigned res = 0; 

    for(int i = 0; num > 0; ++i) 
    { 
     if((num % 10) == 1) 
      res += (1 << i); 

     num /= 10; 
    } 

    return res; 
} 
+0

Czy możesz dać mi przykład? – Nick

+4

Korzystając z szablonów, można obliczać wszystko podczas kompilacji, ponieważ są one kompletne. Czy to jednak pomaga OP osiągnąć cokolwiek? – PlasmaHH

+1

-1: Wątpię w to. Jeśli OP miał LOD, który byłby potrzebny, aby użyć metaprogramowania, mógł po prostu zrobić "const double d = 170.0;" Ponieważ jest on pewny, otrzymując liczbę wejściową w czasie wykonywania, więc metaprogramowanie jest zakończone. –

3

Właściwie jeśli piszesz unsigned int bin_number = 10101010, to jest interpretowany jako liczbę dziesiętną przez kompilator.

Jeśli chcesz napisać binarne litteral w kodzie źródłowym, należy użyć BOOST_BINARY.Then wystarczy go wydrukować przy użyciu cout, dziesiętny jest domyślnym ...

unsigned int i = BOOST_BINARY(10101010); 
std::cout << i; // This prints 170 
+0

Co to jest BOOST_BINARY? – Nick

+0

Niektóre kompilatory również obsługują prefiks "0b" ('i = 0b10101010'), ale z doładowaniem zapewniasz przenośność. – Aurel

+0

Boost jest biblioteką C++, spójrz na http://www.boost.org/. – Aurel

7

Cóż, jeśli to "liczba" jest w rzeczywistości ciągiem pobranym z jakiegoś źródła (odczytanego z pliku lub z użytkownika), który został przekonwertowany na liczbę (myśląc, że jest bardziej odpowiedni dla rzeczywistej liczby), co jest całkiem prawdopodobne, można użyć wartości std::bitset wykonać konwersję:

#include <bitset> 

unsigned int number = std::bitset<32>("10101010").to_ulong(); 

(oczywiście 32 tutaj jest zdefiniowane w implementacji i może być bardziej odpowiednio napisany jako std::numeric_limits<unsigned int>::digits).

Ale jeśli jest to naprawdę numer (zmienna integer) w (bardzo) pierwsze miejsce można zrobić:

#include <string> 

unsigned int number = std::bitset<32>(std::to_string(bin_number)).to_ulong(); 

(używając C++ 11: to_string) Ale to prawdopodobnie nie będzie najbardziej efektywny sposób, ponieważ inni przedstawili bardziej wydajne algorytmy oparte na liczbach. Ale, jak powiedziałem, wątpię, czy rzeczywiście otrzymujesz tę liczbę jako rzeczywistą zmienną całkowitą w pierwszej kolejności, ale raczej odczytaj ją z jakiegoś pliku tekstowego lub od użytkownika.

+0

Dziękuję, to dobra odpowiedź, ale numer nie jest ciągiem, nie mogę używać C++ 11 i poprosiłem o szybkie rozwiązanie! – Nick

+0

@Nick Więc mogę spytać skąd go wziąłeś, oczywiście musisz go skądś pobrać i wątpię, żebyś rzeczywiście przeczytał liczbę binarną, która reprezentuje liczbę zawierającą tylko cyfry 0 i 1, co byłoby śmieciem.To naprawdę tylko ma sens, aby taką liczbę uzyskać z jakiegoś medium tekstowego. Jedynym wyjątkiem jest sytuacja, gdy potrzebujesz stałych binarnych, ale do tego możesz po prostu użyć innej metody (program szablonu gliderkite jest bardzo ładny). Ale w większości przypadków, gdy jest to ciąg znaków, rozwiązanie bitsetowe nie powinno być najwolniejsze (i nie wymaga też C++ 11). –

+0

btw masz mój +1 – Nick

0

Jeśli znasz liczbę cyfr binarnych, że masz do czynienia z i to zawsze stałą i liczba binarna jest w ciągu znaków (jak byłoby gdyby odczytać z pliku lub stdin) w czasie wykonywania (tj Konwersja czasu kompilacji nie jest możliwa), możesz zastosować następujące podejście:

int to_binary(const char* c) 
{ 
    return ((c[0] & 1) ? 0x80 : 0x00) | 
      ((c[1] & 1) ? 0x40 : 0x00) | 
      ((c[2] & 1) ? 0x20 : 0x00) | 
      ((c[3] & 1) ? 0x10 : 0x00) | 
      ((c[4] & 1) ? 0x08 : 0x00) | 
      ((c[5] & 1) ? 0x04 : 0x00) | 
      ((c[6] & 1) ? 0x02 : 0x00) | 
      ((c[7] & 1) ? 0x01 : 0x00); 
} 

Zakłada to stały ośmioramienny numer binarny.nazywane tak:

std::cout << to_binary("10101010") << std::endl; 

Jeśli miał szesnaście numer bitu można nadal używać go:

const char* bin_number = "1010101010101010"; 

// Deal with 16 bits 
std::cout << (to_binary(bin_number) << 8 | to_binary(bin_number + 8)) << std::endl; 

Należy pamiętać, że nie istnieje wyraźne granice kontrolne tutaj i jestem powołując się na fakt, że LSB z "1" ma zawsze wartość 1, a "0" zawsze wynosi 0 (więc nie sprawdza poprawności, że jest to wejście binarne).

Oczywiście jest to dość specyficzne i niezbyt elastyczne, ale działa i jestem nie jestem pewien, że dostaniesz znacznie szybciej.