Kurzusok
/
Python
Python
/
Tanterv
/
Bitenkénti operátorok
Bi

Bitenkénti operátorok ebben a kurzusban: Python

{one: "1 feladat", other: "%{count} feladat"}

A(z) Bitenkénti operátorok fogalomról

A hardver szintjén a tranzisztorok csak be- vagy kikapcsolt állapotban lehetnek: ezt a két állapotot hagyományosan 1-gyel és 0-val jelöljük. Ezek a binary digits, röviden bits. A bits és a binary ábrázolás ismerete különösen fontos a rendszerprogramozóknak, akik alacsony szintű nyelveken dolgoznak.

A számítástechnika történetének nagy részében azonban a programozás fő célja az volt, hogy egyre kifinomultabb módokat találjon erre a bináris valóság elvonatkoztatására. Pythonban (és sok más magas szintű programozási nyelvben) int, float, string és más definiált típusokkal dolgozunk, egészen a hang- és videoformátumokig. Rábízzuk a Python belső működésére, hogy (végül) mindent bitekre fordítson.

Ennek ellenére a bitenkénti operátorok és a bitenkénti műveletek használata néha jelentős előnyt jelenthet a sebesség és a memóriahasználat terén, még egy olyan magas szintű nyelvben is, mint a Python.

Bináris számok bevitele és megjelenítése

Nem meglepő módon a Python tízes számrendszerbeli számokkal kommunikál a felhasználóval, de a programozó felülírhatja ezt az alapértelmezést. Sőt, a Python készséggel elfogad int értékeket binary, hexadecimal vagy octal formátumban, és gond nélkül végez matematikai műveleteket köztük. További részletekért nézd meg a binary-octal-hexadecimal fogalmat.

A bináris számokat 0b előtaggal írjuk le, ahogy a hexadecimális számokhoz a 0x használható (a hex számok tömör módját adják a 4 bites csoportok ábrázolásának), az oktális számokhoz pedig az oct.

Többféleképpen is átalakíthatunk egész számokat bináris stringgé; a változatok abban térnek el, hogy tartalmazzák-e a 0b előtagot, és hogy támogatják-e a bal oldali nullákkal való feltöltést:

# Binary entry.
>>> 0b10111
23

# Converting an int display to binary string, with prefix.
>>> bin(23)  
'0b10111'

>>> number = 23

# Binary without prefix, padded to 8 digits.
>>> format(number, '08b')  
'00010111'

# Same format, but using an f-string.
>>> f"{number} in decimal is {number:08b} in binary and {number:x} in hex" 
'23 in decimal is 00010111 in binary and 17 in hex'

Bitwise Logic

A bools fogalomban a logikai operátorokról volt szó: az and, or és not, amelyeket Boolean (True és False) értékekkel használunk. Ugyanezek a logikai szabályok érvényesek, amikor bitekkel dolgozunk.

A logikai operátorok bitenkénti megfelelőit viszont, azaz a & (and), | (or), ~ (not) és ^ (XOR) operátort a bináris ábrázolás minden egyes bitjére alkalmazzuk, ahol az 1 a True („be"), a 0 pedig a False („ki") jelentést kapja. Talán világosabb lesz egy példa a bitenkénti & operátorra:

>>> x = 0b01100110
>>> y = 0b00101010

>>> format(x & y, '08b')
'00100010'

Csak azok a pozíciók lesznek 1-esek az eredményben, amelyek mindkét bemeneti számban 1-et tartalmaznak.

A bitenkénti &-et gyakran arra használjuk, hogy egyetlen biteket emeljünk ki egy tömörített True/False értékhalmazból, például egy alkalmazás felhasználó által beállítható opciói közül. Így az egyes bitek értéke vezérelheti a program logikáját:

>>> number = 0b0110
>>> number & 0b0001 > 0
False

>>> number & 0b0010 > 0
True

A bitenkénti | (or) esetén 1 kerül az eredménybe, ha a bemenetek valamelyikében 1 van:

>>> x = 0b01100110
>>> y = 0b00101010

>>> format(x | y, '08b')
'01101110'

A ^ operátor a bitenkénti exkluzív vagy (xor) műveleté: 1 kerül az eredménybe, ha a bemenetek valamelyikében szerepel, de nem mindkettőben. Ez a szimbólum ismerős lehet a sets fogalomból, ahol a set szimmetrikus differenciáját jelöli, ami ugyanaz, mint a halmazokra alkalmazott xor. Ha a xor ^ furcsának tűnik, jó tudni, hogy messze ez a kriptográfia leggyakoribb művelete.

>>> x = 0b01100110
>>> y = 0b00101010

>>> format(x ^ y, '08b')
'01001100'

Végül itt van a ~ operátor (a tilde karakter), ami a bitenkénti not: egyetlen bemenetet vesz, és az összes bitet megfordítja, ami talán nem az az eredmény, amire számítottál! Az ábrázolásban minden 1 0-vá változik, és fordítva. A részleteket lásd a következő szakaszban.

Negatív számok és a bináris ábrázolás

A tízes számrendszerbeli ábrázolásban a pozitív és negatív számokat úgy különböztetjük meg, hogy a számjegyek elé + vagy - jelet írunk. Ezeknek a jeleknek a használata bináris szinten nem bizonyult hatékonynak a digitális számítástechnikában, ráadásul felvetette azt a problémát, hogy a +0 nem ugyanaz, mint a -0.

A - és a + helyett minden modern számítógép two's complement ábrázolást használ a negatív számokhoz, egészen a szilíciumlapka szintjéig. Ez azt jelenti, hogy minden bit megfordul, és egy számot negatívként értelmezünk, ha a bal szélső bit (más néven a „legjelentősebb bit", rövidítve MSB) 1. A pozitív számok MSB-je 0. Ennek az ábrázolásnak az az előnye, hogy a nullának csak egy változata van, így a programozónak nem kell -0-val és +0-val foglalkoznia.

A negatív és pozitív számok ilyen ábrázolása bonyodalmat okoz a Pythonban: a nyelv magjában belül nincsenek olyan véges méretű egészek, mint az int32 vagy az int64. A „modern" Pythonban az int értékek mérete korlátlan (csak a hardver kapacitása szab határt nekik), és egy negatív vagy bitenként megfordított szám bal oldalán (elméletileg) végtelen sok 1 áll, ahogy egy pozitív szám bal oldalán korlátlan sok 0.

Emiatt nehéz hasznos példát adni a bitenkénti bitwise not műveletre:

>>> x = 0b01100110
>>> format(x, '08b')
'01100110'

# This is a negative binary (not twos-complement display).
>>> format(~x, '08b')
'-1100111'  

 # Decimal representation.
>>> x
102

# Using the Bitwise not, with an unintuitive result.
>>> ~x
-103

Ez nem az a 0b10011001, amit a rögzített méretű egészeket használó nyelvekben látnánk.

A ~ operátor csak előjel nélküli byte- vagy egésztípusokkal, illetve rögzített méretű egésztípusokkal működik a várt módon. Ezeket a numerikus típusokat olyan külső csomagok támogatják, mint a NumPy, a pandas és a sympy, a Python magja viszont nem.

A gyakorlatban a Python-programozók gyakran csak pozitív számokkal használják a &, |, ^ operátort és a lentebb leírt eltoló operátorokat. A negatív számokkal végzett bitenkénti műveletek sokkal ritkábbak. Az egyik technika, hogy egy negatív értékhez hozzáadjuk a 2**32 (or 1 << 32) értéket, hogy előjel nélküli int-t kapjunk, de ezt nehéz kézben tartani. Egy másik stratégia a ctypes modul használata és C-stílusú egésztípusok alkalmazása, de ez ugyanolyan nehézkes.

Shift operators

A balra toló operátor, x << y, az x összes bitjét y hellyel balra mozgatja, és az új hézagokat nullákkal tölti fel. Vegyük észre, hogy ez számtanilag ugyanaz, mint a számot (2**y)-nal megszorozni.

A jobbra toló operátor, x >> y, ennek az ellenkezőjét teszi. Ez számtanilag ugyanaz, mint az egész osztás: x // (2**y).

Tartsd észben az előző, negatív számokról szóló szakaszt, és azokat a buktatókat, amelyekkel a Pythonban való eltolásuk jár.

>>> x = 8
>>> format(x, '08b')
'00001000'

# A left bit shift. 
>>> x << 2  
32

>>> format(x << 2, '08b')
'00100000'

# A right bit shift. 
>>> format(x >> 2, '08b')
'00000010'
Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg