PDA

View Full Version : [Tutorial] Bit Shifting


Vince
25/04/2011, 12:00 AM
Hallo.

In deze tutorial ga ik uitleggen wat het voordeel is van het gebruik van bitshifts in enums. Als de woorden enum en bitshifting voor jou geen betekenis hebben, lees dan vooral verder.

Wat is een enum?
Een enum - of enumerator in het lang - doet wat je er van verwacht. Het wijst een nummer toe aan de variabelen die er in zitten. Ik betrap mezelf erop dat ik overmatig gebruik maak van enums omdat ze verdomd handig zijn bij het nummeren van dialogs e.d. De kans is dan ook nihil dat je per ongeluk twee dezelfde dialogid's gebruikt.

Standaard wordt bij een enum de operator += 1 gebruikt. Dit nummert telkens verder, zoals in de vorige paragraaf beschreven. Voor deze tutorial gebruiken we echter een andere operator. Namelijk de left shift operator <<= 1. En nu kom ik op mijn volgende stukje:

Wat is bitshifting?
Om te weten wat bit shifting nu precies is, moeten we gaan graven naar de kern van de variabelen: de bits oftewel binary digits. Elk cijfer en elke letter is opgebouwd uit een bepaald aantal bits. Pawn gebruikt 32 bits signed integers. Signed betekent 'positief en negatief'. Unsigned betekent alleen positief. De maximale waarde voor een 32 bit signed integer is 2 147 483 647. Om maar even een voorbeeld te geven:


new var = 65;
new var = 'A'; // Enkele quotes!
new var = 0x41;
new var = 0b1000001


Betekenen allemaal hetzelfde. Het is maar wat je het liefste hebt. Op een bepaald ogenblik zou je mogelijk willen controleren of het getal 65 in de variabele zit. Het feit dat dat hetzelfde is als de letter A is dan puur toeval. Voor deze tutorial gaan wij vooral het laatste heel handig vinden.

Maar wat is dat bitshifting nu juist? Wel, bij bitshifting worden alle bits X aantal plaatsen naar links of rechts opgeschoven. Hier shiften we bijvoorbeeld zeven keer naar links:

0000 0001
0000 0010
0000 0100
0000 1000
0001 0000
0010 0000
0100 0000
1000 0000

Waarvoor is het dan handig?
Zoals ik dus al zei, zijn er 32 bits beschikbaar. 32 bits die ofwel 1 ofwel 0 zijn. 32 bits die we kunnen gebruiken om een ja of een nee op te slaan. 32 bits waarin we kunnen kijken of een speler iets wel of juist niet heeft.

Maar: hiervoor hebben we slechts 1 variabele nodig, en geen 32! Vaak zie ik mensen dit doen:

new bool:var1[MAX_PLAYERS];
new bool:var2[MAX_PLAYERS];
new bool:var3[MAX_PLAYERS];
new bool:var4[MAX_PLAYERS];

Omdat in dit geval telkens alleen 1 of 0 wordt opgeslagen, zijn er altijd 31 bits (meer dan 3 bytes) die gewoon verloren gaan. Dit kunnen we tegen gaan.


enum (<<= 1)
{
var1 = 0b0001,
var2,
var3,
var4
};

new PlayerVar[MAX_PLAYERS];


Er is nu meer code, maar we zijn nu wel 3 MAX_PLAYER variabelen kwijt (en dit kan dus oplopen tot 31)! Om nu een waarde op 1 of 0 te zetten of om een waarde uit te lezen hebben we de bit operators nodig.

Bit Operators
Bitwise AND (&)
Vergelijkt twee getallen op binair niveau. Alleen als beide getallen eenzelfde bit aan (1) hebben zal het eindresultaat ook die bit aan hebben. Bijvoorbeeld:

0000 1001
&
0001 1000
---------
0000 1000

Dit kunnen we dus gebruiken om te kijken of een bepaalde waarde gezet is of niet.

if(PlayerVar[playerid] & var4) // Kijk of de bit waarin var4 zit aan is

Bitwise OR (|)
Vergelijkt twee getallen op binair niveau. Als een van beide getallen een bit aan heeft zal in het eindresultaat ook die bit aan zijn. Bijvoorbeeld:

0000 1001
|
0001 1000
---------
0001 1001


Dit kunnen we dus gebruiken om een waarde toe te wijzen:


PlayerVar[playerid] |= var2; // zet de bit van var2 aan
PlayerVar[playerid] |= var3; // zet de bit van var3 aan

Bitwise NOT (~)
Inverteert alle bits. Bijvoorbeeld:


0000 1001
~
---------
1111 0110


Dit kunnen we gebruiken (in combinatie met de AND operater) om een variable te unsetten (terug op 0 zetten):

PlayerVar[playerid] &= ~var2; // zet de bit van var2 terug op 0

Wat er hier gebeurt is het volgende: de bits van var2 en var3 staan aan, dit zijn dus de 2de en 3de bit. PlayerVar bevat dus het volgende: 0000 0110. Dit getal wordt ge-and met het omgekeerde van var2. Var2 is gelijk aan 0000 0010. Het omgekeerde van var2 is dus: 1111 1101. Wat er dus eigenlijk gebeurt is:

0000 0110
&
1111 1101
---------
0000 0100


Ik gebruik deze methode om na te gaan welke settings de speler heeft ingesteld, in welk team hij zit en welke ziektes hij allemaal heeft. Met deze methode is het dus ook mogelijk om een speler in te delen in meerdere teams door middel van 1 variable. Zo kan je bijvoorbeeld een speler indelen in een normaal team EN in het admin team. Daarna gebruik je simpelweg de and operator om te kijken of de speler in een team zit.

Laatste woord:
Het was al heel laat toen ik deze tutorial typte en ik ben er ook vast van overtuigd dat er gedeeltes bij zitten waar je nog steeds met je handen in het haar zit. Als er vragen zijn, stel ze dan gerust.

Kwarde
25/04/2011, 04:15 AM
Bedankt. Ik wist nou nooit wat '|=' deed, en niemand wou dat maar uitleggen >:D

Jantjuh
25/04/2011, 06:22 AM
Wooo, ingewikkeld O_O
Heb k weer wat nieuws te leren xd Goede tut btw :D

-J

Edit: ooo eigenlijk heel simpel :D

playbox12
25/04/2011, 10:39 AM
Mooie tutorial, Kyosaur's tutorial gaat er iets dieper op in (in het Engels, hij is de persoon die het mij weer geleerd heeft :P). Maar dit ziet er ook duidelijk uit.

Smileys
13/07/2014, 09:01 PM
hm ikzie dat laatste reply in 2011 was, we zijn inmiddels 3 jaar later, is deze manier nog steeds goed of zijn er betere/nieuwere varianten?