MenTaLguY
1/22/2008 10:16:00 PM
It may also help if I explain how each piece works. I realize that
bitwise operations are unfortunately becoming something of a "lost art",
but they are important to understand and everyone should make a special
effort to learn about them.
On Wed, 23 Jan 2008 06:22:02 +0900, Mental Guy <mental@rydia.net> wrote:
> def bitmask(bits)
> ( 1 << bits ) - 1
> end
This creates a sequence of 1s. For example:
bitmask(5) ==
( 1 << 5 ) - 1 == # 1 << n == 2 ** n
32 - 1 == # 32 ( 2 ** 5 ) is binary 100000
31 # 31 is binary 11111
Other examples:
bitmask(1) # => 1 is binary 1
bitmask(3) # => 7 is binary 111
bitmask(6) # => 63 is binary 111111
> def shift_left_width(value, register_width, bits)
> ( value << bits ) & bitmask(register_width)
> end
This shifts a number left a certain number of bits, chopping
it off at a certain width. For example:
shift_left_width(134, 8, 3) == # 134 is binary 10000110
( 134 << 3 ) & bitmask(8) ==
1072 & bitmask(8) == # 1072 is binary 10000110000
1072 & 255 == # 255 is binary 11111111
48 # 48 is binary 110000
Note how the mask controls which non-zero bits are kept from
1072 in order to make 48.
[n.b. In some languages, left shift may have a maximum
width built in, though that is not the case in Ruby. ]
> def circular_shift_left(value, register_width, bits)
> remaining_bits = register_width - bits
> top = shift_left_width(value, register_width, bits)
> bottom = value >> remaining_bits
> top | bottom
> end
Now, the circular version:
remaining_bits ==
8 - 3 ==
5
We are moving 3 to the left in an 8-bit register, which
means that 3 bits wrap around, and the remaining 5 bits
just get moved over.
top ==
shift_left_width(134, 8, 3) == # 134 is binary 10000110
48 # 48 is binary 110000
Note how the upper three bits were discarded, and we moved
the remaining five over by three bits.
bottom ==
134 >> 5 == # 134 is binary 10000110
4 # 4 is binary 100
Notice how we moved the top three bits over and discarded
the other five bits; the three bits we kept are the same
the same three bits that were tossed out in the previous
step.
48 | 4 == # 48 is binary 110000
# 4 is binary 100
52 # 52 is binary 110100
So, our circular shift of 134 in an eight-bit shift register
amounted to:
1. take 134 ( 10000110 )
2. split it into two parts ( 100 00110 )
3. swap them ( 00110 100 )
4. put the result back together ( 00110100 )
-mental