• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed Przesunięcia bitowe

Object Storage Arubacloud
0 głosów
946 wizyt
pytanie zadane 15 czerwca 2018 w C i C++ przez Jakub 0 Pasjonat (23,120 p.)
zamknięte 16 czerwca 2018 przez Jakub 0

Witam, nie rozumiem pewnej sytuacji związanej z przesunięciami bitowymi w lewo, mam taki kod:
 

 char a = 10;
 printf("%d\n",(int)(a<<4));

Zakładając że:

sizeof(char) == 1

Mam dla liczby 10 taką tabelę "przesunięć":

00001010 dla a<<0
00010100 dla a<<1
00101000 dla a<<2 
01010000 dla a<<3 
10100000 dla a<<4
01000000 dla a<<5 
10000000 dla a<<6
00000000 dla a<<7

Wobec tego a<<7 powinno wynosić 0, a daje mi wynik: 1280

Wartość a<<6 powinna być mniejsza niż a<<4 a tak nie jest?

O co tu chodzi, będę bardzo wdzięczny za wytłumaczenie tego :/

 

komentarz zamknięcia: temat wyczerpany

2 odpowiedzi

+1 głos
odpowiedź 15 czerwca 2018 przez RafalS VIP (122,820 p.)
wybrane 16 czerwca 2018 przez Jakub 0
 
Najlepsza
Operand przesuniecia jest promowany do inta, wiec prawdopodobnie operujesz na 32 bitach a nie 8.
komentarz 16 czerwca 2018 przez Jakub 0 Pasjonat (23,120 p.)
No dobra, ale u mnie już long long ma 8B.

Mam:

 ((long long)10)<<38

* wiem że za dużo nie potrzebnych nawiasów ale się chciałem uniezależnić od wszelkich priorytetów operatorów.

i wychodzi:

1038

a dla:

 ((long long)10)<<39

jest:

1039

Gdzie tu sens i gdzie logika :/
komentarz 16 czerwca 2018 przez monika90 Pasjonat (22,940 p.)
zapomniałeś o nawiasach, napisz tak:

std::cout << ((long long)10 << 38) << std::endl;
komentarz 16 czerwca 2018 przez Jakub 0 Pasjonat (23,120 p.)

Faktycznie...

Dobra, to już definitywnie ostatnie pytanie na jakie nie znam odpowiedzi ( pytałem o nie już chyba kilka razy) :

  cout << (((long long)10)<<40) << endl;

-> powyżej przesunięcie dla typu long long więc możemy przesuwać o większe wartości nić dla int'a

 cout << (((char)10)<<26) << endl;

-> powyżej przesunięcie dla typu char, więc dlaczego wynik tego przesunięcia jest poprawny tak jak by się odbywał dla typu int? Dla typu char przesunięcie było by za duże... Jednym słowem kiedy ustawiliśmy wartość jako long long to zwiększyliśmy zakres przesunięcia. Dlaczego więc ustawiając wartość jako char zakresu nie zmniejszyliśmy?

Tylko to mi jeszcze przez długi czas nie daje spokoju, a mam już kompletne dość tematu przesunięć

 

1
komentarz 16 czerwca 2018 przez monika90 Pasjonat (22,940 p.)
edycja 16 czerwca 2018 przez monika90
Wartości małych typów całkowitoliczbowych podlegają promocji zanim wykonane zostaną na nich operacje arytmetyczne. char, signed char, unsigned char, short, unsigned short będą konwertowane do int (lub unsigned int jeśli ich zakres wartości nie jest podzbiorem zakresu int).

Dlaczego tak jest? Chodzi o to by operacje były wykonywane na typie danych, który jest naturalny dla danego sprzętu. Na przykład, komputer ma 16-bitowy arytmometr i nie potrafi wykonywać operacji arytmetycznych na 8 bitowych danych, jedyny sposób - skonwertować je do 16 bitów.
komentarz 16 czerwca 2018 przez Jakub 0 Pasjonat (23,120 p.)
Dobra, to wszystko. Wszystko przeanalizuje od początku i jakoś to będzie ;)
0 głosów
odpowiedź 15 czerwca 2018 przez Chess Szeryf (76,710 p.)
edycja 16 czerwca 2018 przez Chess

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
komentarz 15 czerwca 2018 przez Jakub 0 Pasjonat (23,120 p.)
Mówiąc n-ty bit to liczymy bity od zera, tak?
komentarz 15 czerwca 2018 przez Chess Szeryf (76,710 p.)
edycja 15 czerwca 2018 przez Chess

Tak, popatrz na:

1.3.1 Bit and Byte Order (doc. Intel)

Patrząc na tę tabelę, patrz w ten sposób (od prawej do lewej):
 

0-7
8-15
16-23
24-32

A nie odwrotnie, bo wyjdzie źle (ponieważ w tej tabeli nie ma pokazanego 31 bitu).

Rozpisz sobie np. 32 bity na kartce licząc od 0 do 31 i zrozumiesz w czym rzecz.

Podobne pytania

0 głosów
1 odpowiedź 3,153 wizyt
pytanie zadane 3 czerwca 2018 w Java przez xnerwo Gaduła (3,270 p.)
+3 głosów
3 odpowiedzi 765 wizyt
pytanie zadane 29 czerwca 2015 w C i C++ przez krecik1334 Maniak (58,390 p.)
0 głosów
2 odpowiedzi 98 wizyt
pytanie zadane 3 marca 2021 w C i C++ przez eternal Użytkownik (620 p.)

92,620 zapytań

141,474 odpowiedzi

319,813 komentarzy

62,004 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...