Zobacz sobie dokumentację Intel'a, to będziesz wiedział dlaczego dzieje się tak, a nie inaczej.
https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf
Czytaj od:
7.3.6 Shift and Rotate Instructions
global _main
extern _printf
SECTION .data
output: db 0xa,"%i",0xa,0
SECTION .text
_main:
mov eax,5
shr eax,1 ; sal eax,1
push eax
push output
call _printf
pop eax
pop eax
SECTION .bss
Dla tego kodu (shr) rezultatem będzie 2, a dla sal, 10 (to, co zakomentowane).
dlaczego a<<30 daje wartość ujemną? To oznacza że przesuwamy nie tylko bity wartości ale też bit znaku itd... ? .
Ponieważ operujesz na signed int, a nie unsigned int.
O ile się nie mylę, to jeśli operujesz na 32 bitowym rejestrze, to bit znaku jest ustawiony na 31 bicie, jeśli on jest "zapalony", to liczba, która jest na 31 bicie jest ujemna, a bity od 0 do 30, dodatnia. Oczywiście jeśli operujesz na signed int. Jeśli jednak masz ustawione w kodzie printf('%u'), czyli unsigned int, to wtedy chyba nie ma prawa wystąpić liczba ujemna, więc masz rozszerzony maksymalny zakres w zamian za niemożliwość używania liczb ujemnych.
Dla signed int jest to:
-2^{31} do 2^{31}-1
, a dla unsigned int:
2^{32}-1
.Link1, link2.
; #0
output: db 0xa,"%hi",0xa,0
mov eax,32767
; eax<-- 32767
; #1
output: db 0xa,"%hi",0xa,0
mov eax,32768
; eax<-- -32768
; Liczba w rejestrze się "przekręciła", bo nie obsługuje większej liczby niż 32767, "zapalił"
; się bit znaku, ponieważ jest signed int.
; #2
output: db 0xa,"%hi",0xa,0
mov eax,32800
; eax<-- -32736
; #0, #1, #2 - that is example.
For 16-bit register (signed int):
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
-32768 16384 8192 4096 2048 1024 512 256 128 64 32 16 8 4 2 1
output: db 0xa,"%hi",0xa,0
mov eax,33000
Dla tego przykładu "zapalił" się bit znaku, ponieważ przekroczyliśmy liczbę 32767. Liczba o jeden większa niż 32767 staje się od teraz ujemna (mówimy o int'ach). Na 15 bicie stoi taka liczba -32768 (jest to najbardziej ujemna liczba dla rejestru 16-bitowego (mowa o signed int cały czas)). "Zapalony" bit to bit 15 o wartości maksymalnej ujemnej z rejestru 16-bitowego, czyli -32768. Dalej bity "zapalone" to: 3, 5, 6, 7.
Bit 15 <-- -32768
Bit 3 <-- 8
Bit 5 <-- 32
Bit 6 <-- 64
Bit 7 <-- 128
Po zsumowaniu:
Bit(15+3+5+6+7) = -32536
Bit 15+Bit 3+Bit 5+Bit 6+Bit 7 = -32536
-32767+8+32+64+128 = -32536
Signed Int (16-bit register (word))
Input Different Output (bin) Output (dec)
0 (bit sign)
32767 -32768/32767 0000 0000 0000 0000 0111 1111 1111 1111 32767
1
32768 -32768/32767 0000 0000 0000 0000 1000 0000 0000 0000 -32768
1
32769 -32768/32767 0000 0000 0000 0001 1000 0000 0000 0001 -32767
1
32770 -32768/32767 0000 0000 0000 0010 1000 0000 0000 0010 -32766
1
32780 -32768/32767 0000 0000 0000 1100 1000 0000 0000 1100 -32756
1
33000 -32768/32767 0000 0000 1110 1000 1000 0000 1110 1000 -32536
0
32000 -32768/32767 0000 0000 0000 0000 0111 1101 0000 0000 32000
Dla przykładu:
3300-abs(-32768) = 232
3300-|-32768| = 232
Podałem dwa równoważne zapisy.
Dlatego w powyższym przykładzie trzeba było "zapalić" tyle bitów, aby wyszła liczba 232 dla liczby (input) 3300. Bity "zapalone" dodatnie są od 0 do 14, ponieważ bit 15 stanowi liczbę ujemną, którą jest -32768 (mowa o 16-bitowym rejestrze (signed int)).
16-Bit Register
Bit Sign, Numbers Positive
Numbers
Negative
1 0 0 0 0 0 0 0 1 1 1 0 1 0 0 0
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Number Bit
15Bit = -32768
7Bit = 128
6Bit = 64
5Bit = 32
3Bit = 8
______________+
= -32536