Bittioperaatiot Pythonissa¶
Tässä on lyhyesti esitelty erilaiset
bittioperaatiot
Python-tulkissa. Bittioperaatioiden alkeet (AND, OR, NOT, XOR ja siirto-operaatiot) on esitetty varsinaisessa materiaalissa. Tutustu niihin ennen tätä materiaalia.Laiteläheisessä ohjelmoinnissa bittioperaatioita käytetään mm. oheislaitteiden ohjaamiseen ja niiden kanssa kommunikointiin, joten ne on hyvä hallita.
Siirto-operaatiot¶
Siirto-operaatiot oikealle ja vasemmalle tehdään >>- ja <<-operaattoreilla.
Operaattorin
vasemmalle puolella on arvo jonka bittejä
siirretään ja oikealla on siirtojen lukumäärä. Esim 462 << 2
siirtää jokaista 462:n bittiä 2 pykälää vasemmalle. Kuten aiemmin todettiin, tämä siirto vastaisi neljällä kertomista. Vastaavasti 4032 >> 3
siirtäisi jokaista 4032:n bittiä 3 pykälää oikealle, joka vastaa jakamista kahdeksalla. Tämä on kokonaislukujakolasku, joten desimaaliosa jää vain suoraan pois (ts. työnetään reunan yli). Reunan yli työntymistä tapahtuu myös toisessa päässä jos ollaan tekemisissä rajallisten bittimäärien kanssa - näissä on siis syytä olla tarkkana.>>> luku = 8349
>>> bin(luku)
'0b10000010011101'
>>> luku = luku << 3
>>> luku
66792
>>> bin(luku)
'0b10000010011101000'
>>> luku = luku >> 5
>>> luku
2087
>>> bin(luku)
'0b100000100111'
>>> 4 * luku
8348
Yllä kadotettiin ykkönen, koska se työntyi jaettaessa reunan yli oikealta. Nähdäksesi bittien tippumisen toiseen suuntaan tarvitset Pythonissa hieman lisäkoodia, koska sen binäärit ovat äärettömiä. Alla binääriluku on pidetty 8-bittisenä käyttämällä merkkijonosta ainoastaan 8 viimeistä merkkiä:
>>> luku = 231
>>> luku_b = bin(luku)[-8:]
>>> luku_b
'11100111'
>>> luku = luku << 2
>>> luku_b = bin(luku)[-8:]
>>> luku_b
'10011100'
>>> int(luku_b, 2)
156
>>> luku
924
Loogiset bittioperaatiot¶
Loogisia
bittioperaatiota
ovat AND, OR ja XOR. Digitaalitekniikkansa käyneet tuntevat myös NANDin, ja todennäköisesti varsin intiimisti, mutta Pythonissa sille ei ole omaa operaattoria
. Bitti-AND ja -OR ovat periaatteessa samat kuin niiden muuttujavastikkeet, mutta niitä ei yleensä käytetä ehtolauseissa vaan arvojen manipuloinnissa tavalla tai toisella. Nimiensä mukaisesti ne suorittavat and- ja or-operaatiot jokaiselle bitille
. AND-operaatiossa lopputuloksena on 1 jos molemmat vertailtavat bitit ovat ykkösiä, muuten 0. AND-operaattori on Pythonissa ja C:ssä &
. OR-operaatiossa tuloksena on 0 jos molemmat vertailtavat bitit ovat nollia, muuten 1. Vertailu tuottaa siis uuden bittijonon. OR-operaattori on |
. >>> jono_1 = 0b11011010
>>> jono_2 = 0b00001111
>>> "{:08b}".format(jono_1 & jono_2)
'00001010'
>>> "{:08b}".format(jono_1 | jono_2)
'11011111'
Tässä on käytetty
"{:08b}".format(...)
-lauseketta bin-funktion sijaan, koska bin-funktio hukkaa etunollat ja antaisi AND-operaation tulokseksi '0b1010'. Jos haluat bin-funktion antaman 0b mukaan, voit muokata merkkijonon tämän näköiseksi: "0b{:08b}"
. 8 kertoo tulostettavien bittien määrän. Täyden selkeyden nimissä operaatioista on esitetty animaatiot alla:Näiden lisäksi on vielä XOR-operaatio (exclusive or eli poissulkeva tai). Toisin kuin OR, XOR on tosi vain silloin kun toinen ja vain toinen vertailtavista biteistä on 1. Toisin sanoen XOR antaa 1 silloin kun bitit eivät ole samat, ja 0 kun ne ovat samat. XOR-operaattori on
^
, nyt siis ratkesi sekin mysteeri mihin useimmille tuttu potenssiinkorotusmerkki on varattu (Python käyttää samoja operaattoreita kuin C, ja C varasi sen tähän käyttöön hyvin kauan sitten). >>> jono_1 = 0b11011010
>>> jono_2 = 0b00001111
>>> "{:08b}".format(jono_1 ^ jono_2)
'11010101'
Sama animaationa:
Kuten todettua NANDille ei ole omaa operaattoriaan. Nimensä (not and) mukaisesti sen saa aikaan ottamalla
negaation
AND-operaaation tuloksesta. Negaatiosta kannattaa kuitenkin lukea alta ensin.Negaatio¶
Merkin kääntäminen onnistuu helposti
negaatiolla
, varsinkin kun Python lukee numerot valmiiksi kahden komplementtina.>>> luku = 0b1011
>>> luku
11
>>> ~ luku + 1
-11
Sen sijaan emme suosittele negaatio-operaattorin käyttöä Pythonissa jos haluat nimenomaan ainoastaan kääntää
bitit
ja saada luettavan tuloksen. Negaatio kyllä kääntää kaikki bitit, mutta toimintaa ihmetellessä on tarpeen pitää mielessä, että Python käsittelee negatiivisia kahden komplementtilukuja kuin niissä olisi edessä ääretön määrä ykkösiä (koska Python ei käsittele kiinteän kokoisia binäärilukuja, se ei voi tietää mikä biteistä olisi merkkibitti).>>> luku = 231
>>> bin(luku)
'0b11100111'
>>> bin(~ luku)
'-0b11101000'
Python tulkitsee tuloksen negatiivisena lukuna (koska siinä on äärettömästi ykkösiä edessä). Hämäävyys syntyy siitä, että bin-funktio ei näytä negatiivisia lukuja kahden komplementtina vaan etumerkillisenä
binäärilukuna
, jossa siis -0b kertoo että kyse on negatiivisesta luvusta 11101000 eli luvusta -232 jonka kahden komplementtimuoto olisi 100011000 joka on sama kuin alkuperäisen luvun bitit käännettynä jos niihin tulkitaan eteen nolla: 011100111 (muistaen että negatiivisissa luvuissa etuykköset ovat sama kuin positiivisten etunollat, eli niitä voidaan kuvitella niin monta kuin huvittaa). Tämä hämmentävyys juontaa juurensa siihen, että kun bittien määrää ei ole kiinnitetty, ei pystytä sanomaan tarkoittaako esim 11 lukua 3 vai lukua -1, joten on oltava jokin tapa merkitä milloin luku halutaan tulkita negatiivisena - ja tähän on valittu miinuksen laittaminen binääri-indikaattori 0b:n eteen. Pelkkä bittien kääntö kannattaa oikeastaan tehdä merkkijonon replace-
metodilla
erään OA:n harjoitustehtävän mukaisesti tai XOR-operaatiolla bittijonon kanssa jossa on N kpl ykkösiä, missä N on käännettävän binääriluvun bittien määrä: >>> luku = 231
>>> bin(luku)
'0b11100111'
>>> "{:08b}".format(luku ^ 0b11111111)
'00011000'
Yhteenveto¶
Tässä kaikki mitä tarvitsee tietää kun pelataan pääsiassa binääriluvuilla ja biteillä Pythonissa.
Anna palautetta
Kommentteja materiaalista?