4

Can someone give the simplest solution to convert an integer into a Array of Integer representing its relevant binary digits..

Input  => Output
1      => [1]
2      => [2]
3      => [2,1]
4      => [4]
5      => [4,1]
6      => [4,2]

One way is :
Step 1 : 9.to_s(2) #=> "1001"
Step 2 : loop with the count of digit
         use / and % 
         based on loop index, multiply with 2
         store in a array

Is there any other direct or better solution?

3 Answers 3

8

Fixnum and Bignum have a [] method, that returns the value of the nth bit. With this we can do

def binary n
  Math.log2(n).floor.downto(0).select {|i| n[i] == 1 }.collect {|i| 2**i}
end

You could avoid the call to Math.log2 by calculating successive powers of 2 until that power was too big:

def binary n
  bit = 0
  two_to_the_bit = 1
  result = []
  while two_to_the_bit <= n
    if n[bit] == 1
      result.unshift two_to_the_bit
    end
    two_to_the_bit = two_to_the_bit << 1
    bit += 1
  end
  result
end

more verbose, but faster

Sign up to request clarification or add additional context in comments.

3 Comments

Nice. Okay now I am convinced to upgrade to Ruby 1.9. I want my log2.
+1 ... But: Don't forget to filter out the zeros, for completeness :)
Oops, forgot about the zeroes.
3

Here is a solution that uses Ruby 1.8. (Math.log2 was added in Ruby 1.9):

def binary(n)
  n.to_s(2).reverse.chars.each_with_index.map {|c,i| 2 ** i if c.to_i == 1}.compact
end

In action:

>>  def binary(n)
>>       n.to_s(2).reverse.chars.each_with_index.map {|c,i| 2 ** i if c.to_i == 1}.compact
>>     end
=> nil
>> binary(19)
=> [1, 2, 16]
>> binary(24)
=> [8, 16]
>> binary(257)
=> [1, 256]
>> binary(1000)
=> [8, 32, 64, 128, 256, 512]
>> binary(1)
=> [1]

Add a final .reverse if you would like to see the values in descending order, of course.

3 Comments

Thanks Ray...Yossi suggested -> tap[] .. array = [].tap{|arr| n.to_s(2).reverse.chars.each_with_index {|c,i| arr << 2 ** i if c.to_i != 0}}
@Ray: yeah, the last one is the good (except a final reverse is missing?). Not sure we need to see the tries though ;-)
You're right @tokland, the tries were stupid. Cleaned up now.
0
class Integer
  def to_bit_array
    Array.new(size) { |index| self[index] }.reverse!
  end

  def bits
    to_bit_array.drop_while &:zero?
  end

  def significant_binary_digits
    bits = self.bits
    bits.each_with_object(bits.count).with_index.map do |(bit, count), index|
      bit * 2 ** (count - index - 1)
    end.delete_if &:zero?
  end
end

Adapted from and improved upon these solutions found in comp.lang.ruby.

Some simple benchmarks suggest that this solution is faster than algorithms involving either base-2 logarithms or string manipulation and slower than direct bit manipulation.

2 Comments

log2 version is faster for me. I think this will depend on how big the values you use it on are: how many 'wasted' bits are generated (this will also depend on 32 versus 64bit ruby)
@Frederick, good observation. Your new algorithm does beat mine according to Ideone's timer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.