2012-07-03 5 views
12

Mam trzy wartości bool reprezentujące bity. Chcę mieć całkowitą w postaciTworzenie liczby całkowitej z trzech wartości boolowych jako bitów w C++

true true true = 7 
false true false = 2 

mam

int val = 4*boolVal1 + 2*boolVal2 + boolVal3; 

Czy istnieje inny sposób, może nawet prostsze?

+1

Po prostu fyi, czy "prawda prawdziwa prawdziwa" nie powinna być 7? W przeciwnym razie wszystkie formuły do ​​tej pory są błędne ... – SinisterMJ

+2

'int val = 4 * boolVal1 + 2 * boolVal2 + boolVal3;' da 7, gdy masz true true true, nie 8 –

+0

Prawidłowo, właśnie napisałem źle. Thx za poprawianie! – tzippy

Odpowiedz

27

Może się okazać, że jaśniejsze używać operatory bitowe zamiast mnożenia i dodatkowo:

int val = (boolVal1 << 2) | (boolVal2 << 1) | boolVal3; 
4

Inne niż mnożenie i bitshifting, można również użyć enum udokumentować związek. Zwykle nie warte wysiłku, ale tylko dla kompletności ...

enum Encoding 
{ 
    Flag3 = 1,  NotFlag3 = 0, 
    Flag2 = 1 << 1, NotFlag2 = 0, 
    Flag1 = 1 << 2, NotFlag1 = 0 
}; 

int val = (boolVal1 ? Flag1 : NotFlag1) | 
      (boolVal2 ? Flag2 : NotFlag2) | 
      (boolVal3 ? Flag3 : NotFlag3); 

Po co byś się tym przejmował? Jest to trochę bardziej ogólne, więc możesz potencjalnie zmieniać wartości kodowania później bez dotykania potencjalnie rozproszonego kodu przy użyciu rzeczywistych wartości (na przykład, jeśli zdałeś sobie sprawę, że pominąłeś trochę w porównaniu do formatu jakiegoś pliku lub sieci dane, które musisz przeanalizować, możesz dodać je tylko w jednym miejscu i ponownie skompilować). Oczywiście lepiej jest po prostu zapewnić funkcję pojedynczego kodowania/dekodowania, a jeśli dodajesz nowe flagi, nadal będziesz tego potrzebować.

Chociaż flag1 i NotFlag1 mogą wydawać się bezsensowne, często ma się coś wspólnego z wykluczającymi się wzajemnie wartościami, jak np. Sticky and Floating lub Male and Female, i nie ma żadnego szczególnego powodu, aby zmuszać klientów do sprawdzenia, powiedzmy, Floating as ! Sticky lub Kobieta jako Mężczyzna etc ..

+0

"NotFlag's nie są tu zbyt pomocne. Nadal będziesz sprawdzać '(value & Flag2) == NotFlag2', jeśli chcesz sprawdzić, czy Flag2 jest wyczyszczone. Poza tym '?:' Może tworzyć wolniejszy kod niż mnożenie (rozgałęzienie vs. operacja arytmetyczna).Ponadto uważam, że przydaje się przeciążanie operatorów '|,' i ','^'i' ~ 'dla takich wyliczeń, aby typ był zachowany - nawet mam dla niego makro. – krlmlr

+0

@ user946850: często funkcja (zwłaszcza funkcje C) prosi dzwoniących o zakodowanie parametru z flag, więc rozproszony kod wywołujący - którego liczba może być dowolna, a "czystość" jest bardzo ważna, może LUB razem Flagi i "NotFlag" całkiem szczęśliwie, bez potrzeby testowania flag - to kroki konsolidowane w ramach implementacji wywoływanych funkcji, o wiele łatwiejsze w utrzymaniu. I tak, kiedy wyliczenia są używane jako prawidłowe wartości w kodzie klienta - i to nie tylko do kodowania parametru - właściwe operatory są warte posiadania. –

5

albo można użyć Schemat Hornera:

int val = (((boolVal1 << 1) | boolVal2) << 1) | boolVal3.

to również sprawia, że ​​łatwiej dodawać lub usuwać zmienne od połowy rachunku bez konieczności zmiany wszystkie pozostałe współczynniki.

Jednak może to być trochę mniej oczywiste dla czytelnika.

+1

Nie chodzi o to, że ma to znaczenie, ale jestem ciekawy, czy - przy typowych kompilatorach - może być gorzej z powodu sekwencyjnego zamawiania w ewaluacji: byłoby interesujące wiedzieć, czy któryś z ich optymalizatorów może wygenerować kod, który może być sparametryzowanym na potoku instrukcji procesora ... –

+0

@ Tony, Musiałbyś spojrzeć na kod maszynowy, ale oczekiwałbym, że nowoczesne kompilatory zauważą, że w nawiasach nie ma rozgałęzień i czynią to całkiem czysto. –

2

Jeśli znasz endianness można też użyć zachowanie implementacji zdefiniowane i bitsets, wersja mało endian:

union foo { 
     unsigned int the_int; 
     struct { 
       unsigned int bit3:1 
       unsigned int bit2:1 
       unsigned int bit1:1 
     }; 
}; 

a następnie je ustawić:

foo.bit1 = true; 
foo.bit2 = false; 
foo.bit3 = true; 

i czytać:

foo.the_int; 

Wersja wielko-endianowa ma odwrócone bity i dużo dopełnienia (29 bitów, jeśli unsigned int ma szerokość 32bits) z przodu.