How convert an integer to a bit array

Does anyone have a clever way to convert an integer to an array of bit
values?

For example (using 8 bit integers):

0 => [0, 0, 0, 0, 0, 0, 0, 0]
1 => [0, 0, 0, 0, 0, 0, 0, 1]
2 => [0, 0, 0, 0, 0, 0, 1, 0]
7 => [0, 0, 0, 0, 0, 1, 1, 1]
etc.

I was looking at Array#pack and Array#unpack to do this, but haven’t
figured
it out yet. It just seems like there ought to be a simple way to do
this.

Anybody got a clever idea?

Curt

On Nov 22, 2005, at 4:23 PM, Curt H. wrote:

I was looking at Array#pack and Array#unpack to do this, but
haven’t figured
it out yet. It just seems like there ought to be a simple way to do
this.

Anybody got a clever idea?

Does this help?

("%b" % 5).split("").map { |n| n.to_i }
=> [1, 0, 1]

James Edward G. II

Curt H. wrote:

I was looking at Array#pack and Array#unpack to do this, but haven’t figured
it out yet. It just seems like there ought to be a simple way to do this.

Anybody got a clever idea?

Curt

s = “”
s[0] = 7
s.unpack(“B*”)[0].split("").map{|bit|bit.to_i}
=> [0, 0, 0, 0, 0, 1, 1, 1]

It should be easier than that, though.

On Wed, Nov 23, 2005 at 07:31:02AM +0900, James Edward G. II wrote:

7 => [0, 0, 0, 0, 0, 1, 1, 1]

("%b" % 5).split("").map { |n| n.to_i }
=> [1, 0, 1]

An alternative to (’%b’ % n) is n.to_s(2)

marcel

Curt H. wrote:

I was looking at Array#pack and Array#unpack to do this, but haven’t figured
it out yet. It just seems like there ought to be a simple way to do this.

Anybody got a clever idea?

Curt

irb(main):082:0> x = 7.to_s(2).split(//).map! {|bit| bit.to_i}
=> [1, 1, 1]
irb(main):083:0> x.unshift(0) until x.length == 8

if your number always fit into 8 bit
otherwise this doesn’t work

Regards, Daniel

How about:

num = 50

num.to_s(2).split("").map{ |bit| bit.to_i}

There’s problably some trickery with String.each_with_index you can
do to make the map a little simpler.

Marcel Molina Jr. wrote:

1 => [0, 0, 0, 0, 0, 0, 0, 1]
Curt

x.unshift(0) until (x.size % 8).zero?

marcel

Nah, that’s too much work.

x = ("%08d" % 7.to_s(2)).split(’’).map{ |e| e.to_i }

Replace 8 with the integer size and 7 with whatever number you’re
converting.

Regards,

Dan

On Wed, Nov 23, 2005 at 07:37:25AM +0900, Daniel Sch?le wrote:

etc.
=> [1, 1, 1]
irb(main):083:0> x.unshift(0) until x.length == 8

if your number always fit into 8 bit
otherwise this doesn’t work

You could do this:

x.unshift(0) until (x.size % 8).zero?

marcel

On 11/22/05, Curt H. [email protected] wrote:

I was looking at Array#pack and Array#unpack to do this, but haven’t figured
it out yet. It just seems like there ought to be a simple way to do this.

Anybody got a clever idea?

This way is about 4 times faster than James’ version:

class Integer
def to_ba(size=8)
a=[]
(size-1).downto(0) do |i|
a<<self[i]
end
a
end
end

p 0.to_ba
p 1.to_ba
p 2.to_ba
p 7.to_ba
END

Result:

[0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 1]
[0, 0, 0, 0, 0, 0, 1, 0]
[0, 0, 0, 0, 0, 1, 1, 1]

Ryan

On 11/22/05, Ryan L. [email protected] wrote:

This way is about 4 times faster than James’ version:

For those curious:


| QuickBench Session Started |

100000 Iterations
                           user     system      total        real
  1. 244.to_ba 1.171000 0.000000 1.171000 ( 1.172000)
  2. (“%b” % 244).split(… 4.735000 0.000000 4.735000 ( 4.750000)
  3. s.unpack(“B*”)[0].s… 4.156000 0.000000 4.156000 ( 4.156000)
  4. 244.to_s(2).split("… 4.422000 0.000000 4.422000 ( 4.437000)

Fastest was <1. 244.to_ba>

QuickBench is a little script I wrote, which I may or may not release
into the wild.

The code will follow my name (note how I use the DATA section for the
things to benchmark):

Ryan “Mr. Benchmark” Leavengood

class Integer
def to_ba(size=8)
a=[]
(size-1).downto(0) do |i|
a<<self[i]
end
a
end
end

require ‘quickbench’
s=" "
s[0]=244
QuickBench.go(100000, 22) {}
END
244.to_ba
(“%b” % 244).split(“”).map { |n| n.to_i }
s.unpack(“B*”)[0].split(“”).map{|bit|bit.to_i}
244.to_s(2).split(“”).map{ |bit| bit.to_i}

On Nov 22, 2005, at 4:23 PM, Curt H. wrote:

I was looking at Array#pack and Array#unpack to do this, but
haven’t figured
it out yet. It just seems like there ought to be a simple way to do
this.

Anybody got a clever idea?

Another thought: Ruby’s Integers are already pretty close to a bit
Array. If you only need to index the bits, maybe it’s best not to
convert at all…

James Edward G. II

You guys are awesome… so many good ideas here!

Thanks,
Curt

On 11/22/05, James Edward G. II [email protected] wrote:

bits = Array.new(8) { |i| 7[i] }.reverse!
=> [0, 0, 0, 0, 0, 1, 1, 1]

And the winner by a nose is…


James!!!


| QuickBench Session Started |

300000 Iterations
                           user     system      total        real
  1. 244.to_ba 3.296000 0.015000 3.311000 ( 3.313000)
  2. Array.new(8) { |i| … 2.782000 0.000000 2.782000 ( 2.781000)

| Fastest was <2. Array.new(8) { |i| …> |

I’m glad you posted this because it is elegant and fast. OK, now I’ll
stop spamming this thread with benchmark results :slight_smile:

Regards,
Ryan

On 11/23/05, Ryan L. [email protected] wrote:

I’m glad you posted this because it is elegant and fast. OK, now I’ll
stop spamming this thread with benchmark results :slight_smile:

Cool! Thanks for doing the benchmark.

Curt

On 11/23/05, Curt H. [email protected] wrote:

On 11/23/05, Ryan L. [email protected] wrote:

On 11/22/05, James Edward G. II [email protected] wrote:

bits = Array.new(8) { |i| 7[i] }.reverse!
=> [0, 0, 0, 0, 0, 1, 1, 1]

And the winner by a nose is

James!!!

def to_ba(num, size=8)
(-size+1…0).inject({}) {|x,i| x << num[-i]}
end

to_ba(15)
=> [0,0,0,0,1,1,1,1]

It may be a tad faster, the bigger the array, due to the lack of
reverse. Can someone bench it? I don’t have require ‘quickbench’

Or perhaps, modifying James’:

def to_ba(num, size=8)
Array.new(size) {|i| num[-i+size-1]}
end

Ed

On Nov 22, 2005, at 4:23 PM, Curt H. wrote:

I was looking at Array#pack and Array#unpack to do this, but
haven’t figured
it out yet. It just seems like there ought to be a simple way to do
this.

Anybody got a clever idea?

Last idea:

bits = Array.new(8) { |i| 7[i] }.reverse!
=> [0, 0, 0, 0, 0, 1, 1, 1]

I promise to stop spamming this thread now. :wink:

James Edward G. II