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

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

I've never dealt with bits and bytes, so I'm unable to figure out the first 5 bits and last 3 bits of say 129... supposed to get 16 and 3 or 2 or something... Thank you!

I sort of came up with this, but it's not nice:

#!/usr/bin/perl # $num = 129; $str = unpack("B32", pack("N", $num)); $str =~ s/^0+(?=\d)//; # otherwise you'll get leading zeros print "$str\n"; $fragment = substr $str, 0, 5; #first 5 bytes print "$fragment\n"; $num1=unpack("N", pack("B32", substr("0" x 32 . $fragment, -32))); print "num1=$num1\n"; $fragment = substr $str, 5, 3; #first 5 bytes print "$fragment\n"; $num2=unpack("N", pack("B32", substr("0" x 32 . $fragment, -32))); print "num2=$num2\n";

Replies are listed 'Best First'.
Re: first 5 bits and last 3 bits
by moritz (Cardinal) on Jul 26, 2011 at 12:39 UTC

    The "first 5 bits" of a number really depend on the storage format.

    For example as a 32 bit integer, 129 is represented as 00000000000000000000000010000001, the first 5 bits of which are all zero.

    If that's not what you want, consider converting the number to the string 10000001 by using sprintf and then use substr to extract what you want.

      It's 8 bits
        Not just how many bits, but whether it is big or little-endian.
Re: first 5 bits and last 3 bits
by fisher (Priest) on Jul 26, 2011 at 12:38 UTC
    Use bitmask and bitwise boolean operations.
    fisher% perl -e 'my $byte=129; my $first5=$byte&0xf8; printf "%08b, %d +\n", $byte, $first5;' 10000001, 128
      If you're creating a bitmask, it's clearer to say 0b11111000 than 0xf8.
Re: first 5 bits and last 3 bits
by ikegami (Patriarch) on Jul 26, 2011 at 18:55 UTC
    my $byte = 129; # 0b10000001 = 129 my $most_significant_5 = $byte >> 3; # 0b10000 = 16 my $least_significant_3 = $byte & 0x7; # 0b 001 = 1

    How did I arrive at that? Basically, you want to either

    • Mask out the bits of higher significance than those you want, then shift the bits you want to index 0; or
    • Shift the bits you want to index 0 then mask out the bits of higher significance than those you want.
    is a simplification of ---------------------------------------------------- $byte >> 3 ( $byte & 0xFF ) >> 3 or ( $byte >> 3 ) & 0x1F $byte & 0x7 ( $byte & 0x7 ) >> 0 or ( $byte >> 0 ) & 0x7

    Notes;

    • «0x7» is 0b111 or 23-1. «& 0x7» "keeps" only the least significant 3 bits.
    • «0x1F» is 0b11111 or 25-1. «& 0x7» "keeps" only the least significant 5 bits.
    • «0xFF» is 0b11111111 or 28-1. «& 0x7» "keeps" only the least significant 8 bits.
    • «& 0xFF» is a no-op when dealing with 8-bit values.
    • «>> 0» is a no-op for integers, which is what we're dealing with.
      thank you so much for the answer and education!!!
Re: first 5 bits and last 3 bits
by jpl (Monk) on Jul 26, 2011 at 20:32 UTC
    This posting may win some sort of award for ambiguity. What do "first" and "last" mean? Are the "first" the most significant, and the "last" the least significant? If, as the OP added, "it's 8 bits", which 8 bits? The most/least significant? If you strip away leading 0's, as the OP did, is it the 8 bits whose most significant bit is a 1 (which, of course, may not yield 8 bits)? There are many reasonable suggestions here, just as there are many reasonable interpretations of what the heck the OP wants. It doesn't help that the OP offered several suggestions on what the result should be.

      It doesn't help that the OP offered several suggestions on what the result should be.

      He seems sure of 16, which is indeed the result one gets from taking the most significant 5 bits of an 8 bit number.

      As far as I'm concerned, this clears up the ambiguity, leaving a post that's simply unclear.