2010-06-08 6 views
7

Chcę móc uzyskać dostęp do bitu znaku liczby w C++. Mój obecny kod wygląda mniej więcej tak:Jak mogę uzyskać dostęp do bitu znaku liczby w C++?

int sign bit = number >> 31; 

, który wydaje się działać, dając mi 0 dla liczb dodatnich i ujemnych -1 numerów. Jednak nie widzę w jaki sposób uzyskać -1 dla liczb ujemnych: jeśli 12 jest

0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1100 

następnie -12 jest

1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 0011 

i przesuwanie ich 31 bitów pozwoliłoby

0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 

co oznacza 1, a nie -1, dlaczego więc otrzymam -1, kiedy go zmieniam?

+0

możliwy duplikat (http: // stackoverflow. com/questions/141525/absolute-beginners-guide-to-bit-shifting) – msw

+0

int sign_bit = (int) (liczba> 0); – aviraldg

+5

Dla [uzupełnienia dwójki] (http://en.wikipedia.org/wiki/Two%27s_complement#Complement_of_a_positive_number) (którego używają najbardziej nowoczesne systemy), twoje -12 jest złe. Powinno to kończyć się 0100. –

Odpowiedz

11

Wynik przesunięcia w prawo liczby ujemnej w C++ jest zdefiniowany przez implementację. Tak więc nikt nie wie, co należy zmienić na Twoim komputerze. Myślisz, że powinien to zrobić (1), podczas gdy ja mówię, że może on łatwo stworzyć wzór all-one, który jest -1. Ten drugi nazywa się przesunięciem rozszerzonym o znak. W przesuniętym znaku przesunięcia bit znaku jest kopiowany w prawo, ale nigdy nie jest przesunięty ze swojego miejsca.

Jeśli wszystko, co Cię interesuje, to wartość bitu znaku, a następnie przestań marnować czas, próbując użyć operacji bitowych, takich jak zmiany itp. Wystarczy porównać liczbę do 0 i sprawdzić, czy jest ujemna, czy nie.

+1

To jest naprawdę stary post, ale widziałem to po prostu szukając czegoś innego. Ogólnie zgadzam się z tym, co tu mówisz. Ale są pewne założenia, które poczynił w swoim pytaniu, które mogły przyczynić się do wyniku jego kodu. Można to zrobić niezależnie, zmieniając bit lub po prostu używając maski bitowej, aby sprawdzić bit znaku. –

+0

Nie rozróżnia to -0,0 od +0,0. Musisz uzyskać dostęp do tego znaku bitowego. Zobacz odpowiedź Jana. –

+0

@NeilG Na podstawie tekstu w pytaniu, wydaje mi się, że pytam o liczby całkowite. –

24

Co z tym?

int sign = number < 0;

2

Operator >> wykonuje jakąś arithmetic shift, która zachowuje znak liczby.

+4

Nie. Jakiego rodzaju zmiana jest wykonywana przez operatora '>>' jest zdefiniowany przez implementację. Może być jakakolwiek zmiana. – AnT

+0

@AndreyT: Powiedziałem, że operator '>>' wykonuje przesunięcie arytmetyczne "i dokładnie to robi w tym przypadku, sądząc po opisie OP. Zauważ, że I * nie * powiedział "operator' >> 'zawsze wykonuje przesunięcie arytmetyczne" lub coś podobnego. Być może powinienem być bardziej bezpośredni, ale tak czy inaczej, nie sądzę, że moja odpowiedź zasługuje na pochwałę. – LukeH

+2

@Dowtawerów: Proszę usprawiedliwić się. Wyjaśniłem * dokładnie *, czym jest problem PO. Nie składałem żadnych ogólnych twierdzeń, jak "operator" >> "zawsze wykonuje przesunięcie arytmetyczne"; Wyjaśniłem dokładnie to, co robi operator * >> w tym konkretnym przypadku *. – LukeH

7

Ponieważ przesuwasz podpisaną liczbę całkowitą. Rzutować na całkowitą bez znaku:

int sign_bit = ((unsigned int)number) >> 31; 
4

Dla liczb całkowitych, test number < 0.

W przypadku liczb zmiennoprzecinkowych można również wziąć pod uwagę fakt, że zero ma znak. Oznacza to, że istnieje -0,0, który różni się od +0.0. Aby odróżnić dwa, chcesz użyć std::signbit.

1
bool signbit(double x) 
{ 
    return 1.0/x != 1.0/fabs(x); 
} 

Moje rozwiązanie obsługujące +/- 0.

2

Można użyć cmath bibliotekę

#include <cmath> 

i używać go jak

std::cout << std::signbit(num); 

Ta funkcja uzyskać wartość pływaka jako wkład i wartość bool jako wyjście.

true for negative 
false for positive 

np

std :: Cout < < std :: signbit (1);

daje 0 jako wyjście (fałsz)

ale podczas korzystania z tej funkcji trzeba być ostrożnym o zerowej

std::cout << std::signbit(-0.0); // 512 (true) 
std::cout << std::signbit(+0.0); // 0 (false) 

Wyjście tej linii nie są takie same.

Aby usunąć ten problem, można użyć:

float x = +0.01; 
std::cout << (x >= 0 ? (x == 0 ? 0 : 1) : -1); 

które dają [? Absolute Przewodnik dla początkujących do Bit Shifting]

0 for 0 
1 for positive 
-1 for negative 
-1
bool signbit(double x) 
{ 
    return (__int64)x & 0x8000000000000000LL != 0LL; 
} 

bool signbit(float x) 
{ 
    return (__int32)x & 0x80000000 != 0; 
} 
+0

powoduje niezdefiniowane zachowanie, jeśli 'x' jest poza zakresem' __int64' –