Forum: Ruby How convert an integer to a bit array

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
curt.hibbs (Guest)
on 2005-11-23 00:24
(Received via mailing list)
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
james (Guest)
on 2005-11-23 00:32
(Received via mailing list)
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
vjoel (Guest)
on 2005-11-23 00:36
(Received via mailing list)
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.
marcel (Guest)
on 2005-11-23 00:36
(Received via mailing list)
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
uval (Guest)
on 2005-11-23 00:41
(Received via mailing list)
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
caleb (Guest)
on 2005-11-23 00:41
(Received via mailing list)
>
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 (Guest)
on 2005-11-23 00:45
(Received via mailing list)
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
Daniel.Berger (Guest)
on 2005-11-23 00:53
(Received via mailing list)
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
leavengood (Guest)
on 2005-11-23 00:57
(Received via mailing list)
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
leavengood (Guest)
on 2005-11-23 01:13
(Received via mailing list)
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}
james (Guest)
on 2005-11-23 01:17
(Received via mailing list)
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
james (Guest)
on 2005-11-23 01:25
(Received via mailing list)
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.  ;)

James Edward G. II
curt.hibbs (Guest)
on 2005-11-23 14:12
(Received via mailing list)
You guys are awesome... so many good ideas here!

Thanks,
Curt
leavengood (Guest)
on 2005-11-23 19:03
(Received via mailing list)
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 :)

Regards,
Ryan
curt.hibbs (Guest)
on 2005-11-23 20:32
(Received via mailing list)
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 :)
>

Cool!  Thanks for doing the benchmark.

Curt
ed.howland (Guest)
on 2005-11-24 00:50
(Received via mailing list)
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
This topic is locked and can not be replied to.