Monday, November 8, 2010

Bitwise Comparison

Say you want to have a routine in QUEST SCL that may have to do some things and not others, or vice versa. One way you can specify what sections of code to do is have a series of "flag" that tells the routine what to do and not do. Each flag controls one aspect of the code.

One place I can use this kind of control is in a routine for writing debugging messages to a text file, and optionally to the screen. So for one of these routines, I'd probably want a flag saying whether or not to write to the screen, and another to specify if it's an error message (in which case write to the screen and ignore the other flag), and maybe two more for telling the routine when I'm entering a routine and exiting a routine (to keep track of the call stack, so to speak).

So in this case, I'd need to have four flags I'm setting to true or false every time I call this writing routine. And, if I want to add another flag, I have to change all the calls I've made to this routine to match up with the new flag, since SCL doesn't give you the ability to add optional arguments.


So, rather than deal with this issue of having a flag variable for each option I want to add in a routine, I can instead take advantage of the nature of binary numbers in the computer. Before I continue, keep in mind that I didn't major in computer science or computer anything, so my explanation will probably sound hokey and not quite right.

A computer deals with numbers using binary, where we have a set of numerals that can have a value of zero or one. Each numeral you add on adds a power of two (rather than 10 like in our base-10 system). So, for instance, 1 in binary comes out to 2 to the power of 0, or 1. 10 in binary comes out to 0 to the power of 0 (0) plus 2 to the power of 1 (2) = 2. 100 comes out to 0^0 + 0^1 + 2 ^2 = 4. 1010 comes out to 0^0 + 1^1 + 0^2 + 2^3 = 10

Hopefully, if I did that right, you'll see a pattern where each digit we add onto the left adds another power of 2. 1 = 1, 10 =2 , 100=4, 1000=8, 10000=16, and so on. By seeing this pattern, we can also see that we could use a binary integer to store a series of yes/no flags using 1 for yes and 0 for no (or whatever you want). For instance, 2 + 8 in base 10 equals 10 + 1000 in binary or 1010.

The practical upshot of all this so far is, we can now create a series of flags, each unique flag being a power of two value (1,2,4,8,16,32, and so on), and we can store all the flag values we want to activate by adding the ones we're using together.

So, to define our constants for our message logger:
WriteToScreen 1
ErrorMsg 2
EnteringRoutine 4
ExitingRoutine 8

If we want to write that we're entering a routine we'd just pass in WriteToScreen + EnteringRoutine, which would calculate to 9 in base-10, and our routine could then know which flags to activate based on that number 9.

Now, to break that 9 back up into its parts, we need to go backwards and turn a decimal number back into binary 1's and 0's. Following is a routine that'll do that for us. I'm not sure it's the most efficient, but it seems to work. It works by reading left to right in the powers of two (starting at power 8 - you could increase it if you have more flags to handle). So it starts and sees if 2^8 (256) is less than the num we're trying to break apart. If it is, we turn that flag to true, and subtract 256 from the number until we get down to the last power. In this routine we pass in the flag we want to check against, and return true if the bit we're looking at is true.

Hopefully I didn't bungle the explanation too much, but I really just wanted to have this routine up for future reference, and hopefully it gets you thinking of ways it can help you write more concise or powerful code in SCL.

routine bitwise_or( num : Integer ; against : Integer ) : Integer
Var
i : Integer
pow : Integer
sum : Integer
result : Integer
Begin
sum = num
for i = 8 to 0 by -1 do
pow = 2 ^ i
if( sum >= pow ) then
sum = sum - pow
if( pow == against ) then
result = true
break
endif
endif
endfor
return result
End