Looping through bits in an integer, ruby

bit, integer, loops, ruby

Solution

To determine the length of the longest sequence of consecutive 1's, this is more efficient:

def longest_one_chain(n)
  c = 0
  while n != 0
    n &= n >> 1
    c += 1
  end
  c
end

The method simply counts how many times you can "bitwise AND" the number with itself shifted 1 bit to the right until it is zero.

Example:

                 ______ <-- longest chain
    01011011100001111110011110101010 c=0
AND  0101101110000111111001111010101
        1001100000111110001110000000 c=1, 1’s deleted
AND      100110000011111000111000000
            100000011110000110000000 c=2, 11’s deleted
AND          10000001111000011000000
                    1110000010000000 c=3, 111’s deleted
AND                  111000001000000
                     110000000000000 c=4, 1111’s deleted
AND                   11000000000000
                      10000000000000 c=5, 11111’s deleted
AND                    1000000000000
                                   0 c=6, 111111’s deleted

Problem

I am making a program where one of the problems is that I need to do some analysis of the bit pattern in some integers. Because of this I would like to be able to do something like this: ``` #Does **NOT** work: num.each_bit do |i| #do something with i end ``` I was able to make something that works, by doing: ``` num.to_s(2).each_char do |c| #do something with c as a char end ``` This however does not have the performance I would like. I have found that you can do this: ``` 0.upto(num/2) do |i| #do something with n[i] end ``` This have even worse performance than the `each_char` method This loop is going to be executed millions of times, or more, so I would like it to be as fast as possible. For reference, here is the entirety of the function ``` @@aHashMap = Hash.new(-1) #The method finds the length of the longes continuous chain of ones, minus one #(101110 = 2, 11 = 1, 101010101 = 0, 10111110 = 4) def afunc(n) if @@aHashMap[n] != -1 return @@aHashMap[n] end num = 0 tempnum = 0 prev = false (n.to_s(2)).each_char do |i| if i if prev tempnum += 1 if tempnum > num num = tempnum end else prev = true end else prev = false tempnum = 0 end end @@aHashMap[n] = num return num end ```

Original source