How convert an integer to a bit array


#1

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


#2

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


#3

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.


#4

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


#5

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


#6

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.


#7

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


#8

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


#9

On 11/22/05, Curt H. removed_email_address@domain.invalid 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


#10

On 11/22/05, Ryan L. removed_email_address@domain.invalid 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}


#11

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


#12

You guys are awesome… so many good ideas here!

Thanks,
Curt


#13

On 11/22/05, James Edward G. II removed_email_address@domain.invalid 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


#14

On 11/23/05, Ryan L. removed_email_address@domain.invalid 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


#15

On 11/23/05, Curt H. removed_email_address@domain.invalid wrote:

On 11/23/05, Ryan L. removed_email_address@domain.invalid wrote:

On 11/22/05, James Edward G. II removed_email_address@domain.invalid 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


#16

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