Too Cool for Internet Explorer

Tuesday, August 5, 2008

Bitwising Ruby


This week some students come up with solutions using or appropriate to use bitwise operations, so, it is time to refresh the memory about that subject.

Binary numbers are just a bunch of Zeroes and Ones.

Representing: true / false; on / off, the base of the computer science.

Some Powers of Two:


power of 2 base-10 base-2 (binary)
20 1 1
21 2 10
22 4 100
23 8 1000
...
29 512 1000000000
210 1024 10000000000
211 2048 100000000000
212 4096 1000000000000
...

Binary numbers:

23 = 16 + 0 + 4 + 2 + 1
1 0 1 1 1 = 10111

252 = 128 + 64 + 32 + 16 + 8 + 4 + 0 + 0
1 1 1 1 1 1 0 0 = 11111100


Binary numbers in Ruby:

bin_num1 = 0b10111
bin_num1 = 0b11111100


The bitwise operations in Ruby:

bin1 = 0b100011010101
bin2 = 0b101010000010
puts '- - - - - - - - - - - - - - - - - - - - - - - - -'
puts ' = the bitwise or operation ='
puts '100011010101 <- bin1'
puts '101010000010 <- bin2'
puts '------------------ |'
bin_result = bin1 | bin2
puts sprintf("%12b", bin_result)

puts '- - - - - - - - - - - - - - - - - - - - - - - - -'
puts ' = the bitwise and operation ='
puts '100011010101 <- bin1'
puts '101010000010 <- bin2'
puts '------------------ &'
bin_result = bin1 & bin2
puts sprintf("%12b", bin_result)

puts '- - - - - - - - - - - - - - - - - - - - - - - - -'
puts '= the bitwise exclusive or operation ='
puts '100011010101 <- bin1'
puts '101010000010 <- bin2'
puts '------------------ ^'
bin_result = bin1 ^ bin2
puts sprintf("%12b", bin_result)

puts '- - - - - - - - - - - - - - - - - - - - - - - - -'
puts '= the bitwise negation operation ='
puts '100011010101 <- bin1'
puts '------------------ ~'
bin_result = ~bin1
puts sprintf("%12b", bin_result)
puts '^'
puts '|'
puts '+----- Ruby would like to print 1s forever here'

puts '- - - - - - - - - - - - - - - - - - - - - - - - -'
puts '= the bitwise left shift operation ='
puts '101010000010 <- bin2'
puts '------------------ <<'
bin_result = bin2 << 3
puts sprintf("%12b", bin_result)

puts '- - - - - - - - - - - - - - - - - - - - - - - - -'
puts '= the bitwise right shift operation ='
puts '101010000010 <- bin2'
puts '------------------ >>'
bin_result = bin2 >> 5
puts sprintf("%12b", bin_result)


Parity Check:

It is the easiest way to check if a number is odd or even.

Check the least-significant bit (one's place) in the binary representation:
If it is 0 then the number is even
If it is 1 then the number is odd

def odd_even(number)
puts "#{number.to_s} is #{number & 1 == 1 ? 'odd' : 'even'}"
end

odd_even(8)
odd_even(-3)
odd_even(104)
odd_even(127)
odd_even(32)
odd_even(51)


“Powerful” Bit Operations:

Observe:

11 00001011

22 00010110

44 00101100

If we “shift” the bits one place to the left, and add a 0 at the last place, we double the number.

A final example:

We want to know if a string has just words and spaces, no numbers or special characters:

class String
def are_just_words?
is_false = 0b0
self.split('').collect { |character|
is_false = is_false | ((' '.eql? character or
(65..90).include? eval("?#{character}") or
(97..122).include? eval("?#{character}") or
(192..255).include? eval("?#{character}"))? 0b0 : 0b1)
}
is_false == 0b0 ? true : false
end
end

puts 'Atenção eloqüente ortográfico filosófico'.are_just_words?

Returns true

Now try to include numbers and / or special characters and see what happens.