BITWISE OPERATIONS

by Del

I would recommend you to read the JB help file on "Bitwise Operations" if you are not familiar with binary numbers or Boolean operations.

It's a well known fact that that deep in the engine room of your PC calculations are carried out in binary arithmetic. We are all protected from this by JBasic. Unfortunately for this topic we can't stay protected.

To make life easy I intend to limit integers to 15 or less which gives the equivalent of four bits. Thus we can represent the decimal integer 3 as 0011.

If you look at the binary form you can see four bits each of which is either 0 or 1. We can call these a binary set. Suppose you have four check boxes These can have the status set or reset. These status values can also be represented by 1 and 0. So the status of the check boxes can be represented by these four digits. They can also represent four flags which can be true or false. In the same way that we can represent a decimal integer as a binary number we can represent a binary set as a decimal integer. Note that we have to do this if we to use the set in JB.

One operation you would need is to change one of the bits to SET it ( to change it to 1). This is where bitwise operations come in. This operation is given by the expression

a = a OR 2^bit

where a is the number and bit refers to the number of the bit be changed. (Note that bits are numbered from the right, Bit(0) is the first bit. 2 ^ 2 represents 2 * 2 and 2 ^ 3 represents 2 * 2 * 2)

So  if a is      dec: 6     bin: 0110 and we want to set bit(3) which is the first bit we want 2 ^ bit ( that is 2^3 or 2 cubed) which is
                 dec: 8     bin: 1000
so  6 OR 8 is    dec: 8     bin: 1110

So we have set the first bit. ( OR is true if either of two bits is true.)

Similarly we want to be able to RESET a bit. The expression is a little more complicated. Incidentally the bit stays set if already set

a = a AND (a XOR 2 ^ bit)
So if  a is      dec: 9     bin: 1001    and we want to reset bit(3) which is
                 dec: 8     bin: 1000
then a XOR 8 is  dec: 1     bin: 0001

Just a few words about these expressions. I have used the term 2 ^ bit. You could use this but I used it to show how I got 8. In an actual code you would probably use the integer. I have now used the three Boolean operators described in the JB help file in the above.

The other tool you will need is a routine to tell you the value of your flag. This is the BIT operation.

a = (a AND 2 ^ bit) / 2 ^ bit
So if  a is      dec: 10     bin: 1010   and we want the state of bit(3) then
a AND 8  is     dec: 8       bin: 1000
which is        dec: 8       bin: 1000

Which if we divide by 8 is 1 so the required bit is 1( or true).

You will see that the expression calculates 2 ^ bit twice. Please don't do it that way You only need to calculate once (do as I say not as I do ).

To explain the last line of the calculation let me tell about another trick. If we divide 8 by 2 we get dec: 4 bin: 0100.

The effect on the binary figures is called RIGHTSHIFTING. You lose the original bit(0) and a 0 is put in bit(3). If you divide by 8 it is the equivalent of RIGHTSHIFTING 3 times.

You can also have LEFTSHIFTING. In this case you multiply by 2. A slight problem is that you may have a bit overflowing to the left.

Thus if you multiply  dec: 10     bin: 01010       ( Note I have shown 5
bits )
by 2 you get          dec: 20     bin: 10100

(LEFTSHIFTING and RIGHTSHIFTING may seem a bit trivial. Some other languages actually have these operators. Unfortunately in JB you have to use normal arithmetic.)

The way to get rid of the leading bit is to MASK it

                      dec: 20     bin: 10100
    AND               dec: 15     bin: 01111
   gives             dec:  4      bin: 00100

This last technique is called MASKING. To select the last 4 bits from the set of bits you AND bin: 1111. This is a general form of the BIT operation above. To give a better idea I will use 8 bits this time.

 
If            a is   dec: 186     bin: 10111010       and we want to mask the last four bits the mask is          dec: 15     bin: 00001111             then
a and mask is        dec: 10     bin: 00001010       and the four masked bits are 1010.

If             a is  dec: 186     bin: 10111010 
mask =               dec: 240     bin: 11110000     We can also mask any other bits.
a and mask is        dec: 176     bin: 10110000 . The four masked bits are not changed.

If we divide by 8 we have
                     dec: 13        bin: 00001111

Thus masking separates the bits masked in the original. Note that we end up with another integer. We have used a single integer as a poor man's array. Masking can also select bits for testing even they are not together.

You could also separate the data into 8 bit chunks. You could then use of these chunks to save ASCII code and make your own strings. OK I'm only kidding but this is fundamentally how it is done.

I think that the main problem with bitwise programming is that integers are displayed in decimal values. This hides the underlying binary sets. This can be avoided in part by using one of the many functions of the type shown below. I would this as a function to be used as a debugging aid. You can always calculate the value of a bit by using 2^ bit. Thus bit(7) is 2^7 or 128.

Bitwise operations are of key importance in the engine room. They are used in binary arithmetic, They do not often become obvious when you are using JB. Occasionally you get a peek. For example in the JB help file look in the page for "Graphic Commands". You will find in the first option for colour sixteen colours are defined. Could this possibly represent 4 bit integers? The next colour option describes "red(0-255) green(0-255) blue(0-255)". Now I know that these represent integers. An 8 bit integer for each colour giving altogether a 24 bit integer. I remember from my distant past using XOR commands and other bitwise commands to play with RGB colours. Finally look at the item on "rule" for graphics. Sixteen Windows constants? I know that Windows constants are integers in this case 4 bit integers. I also suggest you look at the constants names. I don't pretend to know what they mean but there seem to be plenty of "XOR"'s and "NOT"'s.

The Boolean function XOR has an interesting property.

                     dec: 5      bin: 0101
     XOR             dec 15       bin 1111
    gives            dec: 10      bin 1010

All the bits are swapped. This is complementing. It is also the equivalent bitwise form of the Boolean NOT operation.

If you repeat the operation of course you finish with the original bit set. This is true of any XOR operation with any bits. If you repeat it you return to the original integer.

I use this function as a debug code.

function dectobin$(num, max)
    'function to display binary value of integer num
    'max is the length of the integer
    strnum$ = str$(num)  'we want to display this later
    for i = 0 to max - 1
        res$ = str$(num and 1); res$ 'add LCB to res$
        num = int(num/2)                    'rightshift
    next i
dectobin$ = "dec: "; strnum$;"     bin: "; res$
end function

There is nothing very special about this function. I have seen several different versions of it. The only thing I would point out is the line

        "res$ = str$(num and 1); res$" .

It masks the final bit of num and the result can be added to res$ by simply the bit to a string.

In LB Newsletter 111 Norman wrote an article titled "Binary Numbers". In it he coded a Horse Racing Game. This has been mentioned on the JB Forum. I was looking for example to use for bitwise operations. With Norman's permission I include my version. Apart from a few minor changes in indexing I realized that his GOSUB GETBIN was not necessary. I made a change in his UPDATE to extract the bits directly and add to the pos$ array. My version is shown below. Because of this I could remove a few lines of code. Out of curiosity I timed both versions of the code and and found that my code was a little faster.

 [UPDATE]
   count=0        'used to count the number of winners in a race
   for k = 0 to 7
      pos(k) = pos(k) + (1 and num)                                    'DEL:
FIND STATE OF LCB (BIT AT FAR RIGHT)
      num = int(num / 2)                                               
          'DELS PATENT rightshift

      if pos(k)=750 then            'check if finish line has been reached
         winner(k)=1                'indicate if a winner
         fin=1                    'indicate that the race is over
         count=count+1        'count number of horses reaching finish together
      end if
   next k
   RETURN

This all sounds very smug. In defense of Norman his code was a demo. His code is probably easier to follow than mine and I recommend his article. Quite apart from this the horses require about two seconds to complete the course. The last thing the program needs is to be spead up.

Finally the classic thing to do with bitwise operations involves sets ( Venn diagrams and such like. If you have never heard of these don't worry your life will not be ruined ). I have deliberately called groups of bits sets. For example 8 bits can represent a set with 8 elements. The universal set would be 11111111 and the empty set 00000000. So a value of 1indicates that an element is in the set and a 0 that it isn't. You can find the intersect of two sets by ANDing them and the union by ORing them. Unfortunately I can not think of a use for this at the moment. i think that it may have some applications in game programming.

I think that direct use of bitwise operators will be not very common but they can have a useful part to play. At least I hope I have given you a different view of binary numbers and integers.

There was a series of posts in the JB forum in "JB Programming Discussions" under the title "Binary programs". In particular DaveG produced a series of functions for logic operations which may find more practical than my versions.