Mai mult
Ce schimbare la nivel de bit (bit-shift) operatorii și cum funcționează ele?
Am'am fost încercarea de a afla C în timpul meu liber, și alte limbaje (C#, Java, etc.) au același concept (și de multe ori aceiași operatori) ...
Ceea ce am'm întrebam, la un nivel de bază, ceea ce face pic-shifting (<<
, >>
, >>>
) fac, ce probleme poate să-l ajute rezolva, si ce chestii trage cu urechea în jurul valorii de cot? Cu alte cuvinte, un incepator absolut's ghid de biți deplasare în toată bunătatea.
1334
9
Bit deplasare operatorii de a face exact ceea ce sugerează și numele lor. Ei trecerea de biți. Aici's un scurt (sau nu-așa-scurtă) introducere la diferite tura de operatori.
Operatorii
>>
este media aritmetică (sau semnat) shift din dreapta operatorului.<<
este o schimbare la stânga operatorului, și satisface nevoile de atât de logică și aritmetică schimburi.Toți acești operatori pot fi aplicate la valori întregi (
int
,timp
, eventualscurt
șioctet
sauchar
). În unele limbi, aplicarea schimbare operatorii la orice tip de date mai mici decâtint
redimensionează automat operand să fie unint
.Rețineți că
<<<
nu este un operator, pentru că ar fi redundant.De asemenea, rețineți că C și C++ nu fac distincție între dreptul de schimbare operatorii. Acestea oferă doar
>>
operator, și chiar schimbarea de comportament este punerea în aplicare definite pentru semnat tipuri. Restul de răspunsul utilizează C# / Java operatori.(În toate de masă C și C++ implementări inclusiv ccg și zăngănit/LLVM, `>> pe a semnat tipuri este aritmetică. Un cod nu își asumă acest lucru, dar e't ceva standard garanții. L's nu nedefinit, deși; standard necesită implementări de a defini într-un fel sau altul. Cu toate acestea, stânga schimburi de negative semnat numere e comportament nedefinit (semnat integer overflow). Deci, dacă aveți nevoie de aritmetică la dreapta shift, l's, de obicei, o idee bună de a face ceva-deplasarea cu nesemnate tipuri.)
Shift stânga (<<)
Numerele întregi sunt stocate în memorie, ca o serie de biți. De exemplu, numărul 6 stocate ca un 32-bit
int
ar fi:Schimbarea acestui model de biți la stânga cu o poziție (
6 << 1
) ar rezulta în număr de 12:După cum puteți vedea, cifrele au deplasat la stânga cu o poziție, și ultima cifră din dreapta este umplut cu un zero. S-ar putea, de asemenea, rețineți că schimbarea stânga este echivalentă cu înmulțirea cu puteri ale lui 2. Deci
6 << 1
este echivalent cu6 * 2", și " 6 << 3
este echivalent cu6 * 8
. O buna optimizare compilatorul va înlocui înmulțiri cu schimburi atunci când este posibil.Non-circulară trecerea
Vă rugăm să rețineți că acestea sunt nu ture circulare. Schimbarea acestei valori la stânga cu o poziție (
3,758,096,384 << 1
):rezultate în 3,221,225,472:
Cifra care devine mutat "off the end" este pierdut. Nu înfășurați în jurul valorii de.
Logic dreapta shift (>>>)
Logic shift din dreapta este invers la stânga shift. Mai degrabă decât se deplasează biți la stânga, ei pur și simplu muta la dreapta. De exemplu, deplasarea în număr de 12:
la dreapta cu o poziție (
12 >>> 1
) va primi înapoi noastre originale 6:Deci, vedem că deplasarea la dreapta este echivalentă cu divizia de puteri ale lui 2.
Pierdut biți sunt plecat
Cu toate acestea, o schimbare nu poate revendica "pierdut" de biți. De exemplu, dacă ne-am schimba acest model:
la stânga 4 pozitii (
939,524,102 << 4
), vom obține 2,147,483,744:și apoi trecerea înapoi (
(939,524,102 << 4) >>> 4
) vom obține 134,217,734:Nu putem primi înapoi valoarea inițială după ce ne-am pierdut de biți.
Aritmetică dreapta shift (>>)
Aritmetica dreapta shift este exact ca logic shift din dreapta, cu excepția în loc de umplutură cu zero, tampoane cu cel mai semnificativ bit. Acest lucru este pentru că cel mai semnificativ bit este semnul ** bit sau bit care distinge numerele pozitive și negative. De umplutură cu cel mai semnificativ bit, aritmetica dreapta shift este semn de conservare.
De exemplu, dacă am interpreta acest model de biți ca un număr negativ:
avem numărul -2,147,483,552. Trecerea aceasta spre dreapta 4 poziții cu aritmetica shift (-2,147,483,552 >> 4) ne va da:
sau numărul -134,217,722.
Deci, vedem că ne-am păstrat semn de numere negative prin utilizarea aritmetică shift din dreapta, mai degrabă decât logică shift dreapta. Și din nou, vom vedea că suntem efectuarea divizia de puteri ale lui 2.
Las's spune ca avem un singur octet:
Aplicarea unei singure stânga bitshift ne devine:
Cea mai din stânga zero a fost mutat din octet, și un nou zero a fost anexată la capătul din dreapta al octet.
Biți don't rollover; ele sunt aruncate. Asta înseamnă că dacă ai plecat schimbare 1101100 și apoi la dreapta shift, ai castigat't obține același rezultat înapoi.
Deplasarea la stânga cu N este echivalentă cu înmulțirea cu 2N.
Deplasarea la dreapta cu N este (dacă utilizați [cele' complement][1]) este echivalentă cu împărțirea la 2N și rotunjirea la zero.
Bitshifting poate fi folosit pentru un incredibil de rapid, înmulțire și împărțire, cu condiția să lucrați cu o putere de 2. Aproape toate low-level rutine grafice utilizarea bitshifting.
De exemplu, drumul înapoi în zilele de demult, am folosit modul 13h (320x200 cu 256 culori) pentru jocuri. În Modul 13h, memoria video a fost pus secvențial per pixel. Asta a însemnat pentru a calcula locația pentru un pixel, ar trebui să utilizați următoarele matematica:
Acum, înapoi în această zi și de vârstă, viteza a fost critică, așa că ne-ar folosi bitshifts de a face această operațiune.
Cu toate acestea, 320 nu este o putere a lui doi, astfel încât pentru a obține în jurul valorii de acest lucru trebuie să aflăm ce este o putere a lui doi care adună face 320:
Acum avem posibilitatea de a converti în stânga schimburi:
Operații la nivel de bit, inclusiv pic de schimbare, sunt fundamentale pentru nivel scăzut de hardware sau de programare. Dacă ai citit o specificație pentru un dispozitiv sau chiar unele binare formate de fișiere, veți vedea octeți, cuvinte și cuvinte, împărțite în non-byte aliniat bitfields, care conține diferite valori de interes. Accesarea acestor pic-câmpuri de citire/scriere este cea mai comună utilizare.
Un simplu exemplu real în grafica de programare este că un 16-bit pixel este reprezentat după cum urmează:
Pentru a ajunge la verde valoarea pe care ar face acest lucru:
Explicație
În scopul de a obține valoarea de verde, care începe de la offset 5 și se termină la 10 (respectiv 6-biți), trebuie să utilizați un (bit) masca, care atunci când este aplicat împotriva întregii 16-bit pixel, va ceda doar de biți suntem interesați.
Masca corespunzătoare este 0x7E0 care în binar este 0000011111100000 (care este 2016 în zecimal).
Pentru a aplica o masca, puteți folosi ȘI operatorul (&).
După aplicarea masca,'ll end up cu un număr de 16 de biți, care este de fapt doar o 11-numărul de biți încă de la MSB este în cea de-a 11 biți. Verde este, de fapt, doar 6-biți, deci, avem nevoie pentru a scala în jos, folosind o dreapta shift (11 - 6 = 5), prin urmare, utilizarea de 5 ca offset (
#define GREEN_OFFSET 5
).De asemenea, comuna este folosind pic schimburi de repede înmulțire și împărțire cu puteri ale lui 2:
Bit de Mascare & Trecerea
Cam schimbarea este adesea folosit în nivelul scăzut de programare grafică. De exemplu, un anumit pixel valoare de culoare codificate într-un 32-bit cuvânt.
Pentru o mai bună înțelegere, aceeași valoare binară etichetate cu ce secțiuni reprezintă ce culoare parte.
Las's spune, de exemplu, vrem să ajungem verde valoarea acestui pixeli de culoare. Putem obține cu ușurință că valoarea de mascare și deplasare.
Masca noastre:
Logic
&
operatorul se asigură că numai valorile în cazul în care masca este 1 sunt păstrate. Ultimul lucru de care avem acum de-a face, este de a ajunge la valoare întreagă prin schimbarea tuturor acestor biți la dreapta de 16 locuri (logical shift dreapta).Et voilá, avem întreg ce reprezintă cantitatea de verde în pixeli de culoare:
Acest lucru este adesea folosit pentru codare sau de decodare formate de imagine ca jpg
,
png,
...`.Unul te-am prins este că următoarele este punerea în aplicare dependente (în conformitate cu standardul ANSI):
x poate fi acum 127 (01111111) sau încă -1 (11111111).
În practică, se's, de obicei acesta din urmă.
Am scris sfaturi și trucuri numai, ar putea găsi utile în teste/examene.
n = n*2
:n = n<<1
n = n/2
:n = n>>1
n |= (1 << x)
x&1 == 0
(chiar)Rețineți că, în implementarea Java, numărul de biți pentru a schimba este în mod'd de dimensiunea sursei.
De exemplu:
este egal cu 2. S-ar putea aștepta trecerea de biți pentru dreptul de 65 de ori ar fi zero totul, dar's, de fapt, echivalentul a:
Acest lucru este valabil pentru <<, >> și >>>. Nu am încercat-o și în alte limbi.
Unele Utile Pic Operarea/Manipularea în Python. Implementat @Ravi Prakash răspunsuri în python.
Fi conștienți de faptul că doar 32 de biți versiune de PHP este disponibil pe platforma Windows.
Apoi, dacă ai, de exemplu, shift << sau >> mai mult de 31 de biți, rezultatele sunt unexpectable. De obicei, numărul original, în loc de zerouri vor fi returnate, iar acesta poate fi un foarte dificil bug.
Desigur, dacă utilizați versiunea pe 64 de biți de PHP (unix), ar trebui să evite trecerea prin mai mult de 63 de biți. Cu toate acestea, de exemplu, MySQL folosește 64-bit BIGINT, așa că nu ar trebui să existe probleme de compatibilitate.
UPDATE: Din PHP7 Windows, php construiește sunt în cele din urmă capabil de a utiliza complet pe 64 de biți numere întregi: Dimensiunea de un număr întreg este dependente de platformă, deși o valoare maximă de aproximativ două miliarde de euro este de obicei o valoare (ca's de 32 de biți semnat). Platforme de 64-bit, de obicei, au o valoare maximă de aproximativ 9E18, cu excepția Windows înainte de PHP 7, unde a fost mereu pe 32 de biți.