http://www.perlmonks.org?node_id=994008

wirito has asked for the wisdom of the Perl Monks concerning the following question:

Hello fellow monks, I'm storing values in a bitwise manner for speed up comparations. I can have 0 or more values in the 0..8 range, so I can store it this way:
$bits |= (1<<$val)
When 1 single bit is set I want to retrive the original $val. So currently I have this implemented:
if( unpack( "%16B*", pack("n", $bits)) == 1 ) { my $ret = 0; while (!($bits & 0x1)) { $ret++; $bits >>= 1; }; return $ret; };
I don't know why, but the while loop seems ugly. Could you enligthen me with a more perlish way to do this? PS: I hope the title is not so much confusing.

Replies are listed 'Best First'.
Re: Which bit is set? (inverse of (1<<$value) operator)
by BrowserUk (Patriarch) on Sep 17, 2012 at 11:27 UTC

    1. If only 1-bit will ever be set:

      Use a lookup table:

      %lookup = map{ 2**$_ => $_ } 0 .. 63;; $flags = 0;; $flags |= 1<<(rand 64);; print "The flag set is:", $lookup{ $flags };; The flag set is: 12
    2. If multiple flags can be set:

      Some form of loop is necessary to avoid an impossibly large lookup table:

      $flags = int rand( 2**64 );; print for grep $flags & 1 << $_, 0 .. 63;; 49 50 51 54 55 57 58 59 printf "%u\n", $flags;; 1066790161733386240 $t = 0; print $t += 1<<$_ for grep $flags & 1 << $_, 0 .. 63;; 562949953421312 1688849860263936 3940649673949184 21955048183431168 57983845202395136 202099033278251008 490329409429962752 1066790161733386240

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    RIP Neil Armstrong

      Many thanks!

      The lookup idea is nice and clean. I will use it as I only have 9 different bits.

      However, your second option is the one I was (foolish) looking for. In my code, this could be the line:

      # return the first less significant bit set. return $_ for grep { $bit & 1<<$_ } (0..8)';
Re: Which bit is set? (inverse of (1<<$value) operator)
by grizzley (Chaplain) on Sep 17, 2012 at 11:17 UTC
    In description of unpack there is following method to count number of bits:
    # Count the bits in a chunk of memory (e.g. a select vector) unpack( '%32b*', $mask );
    Update: sorry, I misunderstood question. If you have string of bits with one bit set, then you could try just $bitstring =~ /1(0*)$/; $originalvalue = length($1)+1;
      Nope, it's a two-byte int, not a strings filled with 0's and 1's.