|Written by Ian Elliot|
|Thursday, 11 February 2016|
Page 1 of 2
The bitwise operators
As you would expect the not operator has the highest priority.
Notice that there are also corresponding logical operators &&, || and ! that only work with Boolean values and not bit patterns.
If you are more familiar with other languages you might well confuse ^ with raise to a power.
The bitwise operators work with numeric data which is converted from floating point to a 32-bit integer, operated on and then converted back to floating point. As a floating double can store a 32-bit integer without loss of precision everything works transparently as long as you stay within the 32-bit limit.
works out Not(a)=0F and b i.e. 0F & FF which is F. You should see the result 15 in decimal displayed.
Notice that bit manipulation is usually easiest to try out using hexadecimal notation e.g. 0xF is 15 in decimal.
So what happens if you go over the 32-bit limit?
In fact strange things start to happen before you reach the 32-bit limit because the 32-bit value is signed and this means that if the highest bit is one the returned value is negative.
displays 0xFFFFFFF which is what you would expect. Notice that toString(16) converts the floating point number to a hex string.
Now try adding one more F to both values i.e. a full 32-bit value all set to one. The result displays as -1 which might not be what you expect but it is perfectly correct.
The result of anding two full 32-bit values both set to one is a 32-bit value with all bits set to one but as the 32-bit value is interpreted as a signed value this converts to -1 (twos complement).
You don't have to worry about this too much as the bit pattern corresponding to -1 is 32 bits all set to one so everything should carry on working is you use the value for further bit manipulation.
Now consider what happens if you add one more F to the values. In this case the values are 36 bits all set to one and the result should also be 36 bits all set to one - but no.
Both the a and b values are converted to 32-bit values the two values are anded together and the result is a 32-bit result i.e. -1 as before.
Beyond 32 bits
So what happens if you try to work with bitwise operators on values that aren't representable as 32-bit integers?
It ignores all fractional parts by truncation.
If the value is larger than a 32-bit integer can store then the result is 32 bits all set to one i.e. -1 in twos complement.
If the value is a fraction smaller than one then the result is zero.
If the value is infinity (plus or minus) or NaN then the result is zero.
You will also be pleased to learn that true evaluates to one and false to zero so you can use the bitwise logical operators on Boolean values. Just about every other possible value returns 0.
So what do you use the bitwise logical operators for?
In many cases you have the problem of setting or clearing particular bits in a value. The value is usually stored in a variable that is usually regarded as a status variable or flag.
You can set and unset bits in a flag using another value usually called a mask that defines the bits to be changed.
For example if you only want to change the first (least significant) bit then the mask would be 0x01.
If you wanted to change the first and second bits the mask would be 0x03 and so on.
If you find working out the correct hexadecimal value needed for any particular mask then you could use the parseInt function with a radix of two. For example:
sets a to 0x01 and
sets a to 0x03 and so on.
In general just write down a string of zeros and ones with a one in the positions you want to change and use parseInt to convert to a mask value.
Ok now that you have a mask what do you do with it?
Suppose the variable mask contains a value that in binary has a one at each bit location you want to change. Then
returns a bit pattern that the mask specifies set to one. Notice that the bits that the mask doesn't specify are left at their original values.
sets result to 0xFFF3 i.e. it sets the first (least significant) two bits.
If you use
then the bits specified in the mask are set to zero - or unset if you prefer. Notice that you have to apply a not operator to the mask.
sets result to 0xFFFC i.e. it unsets the first two bits.
As well as setting and unsetting particular bits you might also want to "flip" the specified bits i.e. negate them so that if the bit was a one it is change to a zero and vice versa. You can do this using the XOR operator
flips the bits specified by the mask.
sets result to 0xFFFC because it changes the lower two bits from ones to zeros. Again bits not specified by the mask are unaffected.
Of course in each case you don't have to use a variable to specify the mask you could just us a numeric literal.
For example instead of:
you can write:
Also if you want to update the flag rather than derive a new result you can use &=, |= and ^= to perform the update directly.
For example, instead of
you can use:
|Last Updated ( Saturday, 01 September 2018 )|