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

Have a hex value of 6bf

0110 | 1011 | 1111

I'd like to flip it to:

1111 | 1101 | 0110 = fd6

I've looked at "pack/unpack" but cannot figure it out.
Thank you

Replies are listed 'Best First'.
Re: LSB to MSB
by Eliya (Vicar) on Aug 07, 2011 at 06:25 UTC

    Here's one way to do it (via an "ASCII-fied" bitstring):

    $ perl -e 'printf "%x\n", unpack("v",pack("b12",scalar reverse unpack( +"b12",pack("v",0x6bf))))' fd6

    or, if you don't mind the trailing zero (this operates on 16 bit instead of 12, i.e. 0x06bf -> 0xfd60)

    $ perl -e 'printf "%x\n", unpack("n",pack("B*",unpack("b*",pack("v",0x +6bf))))' fd60
Re: LSB to MSB
by davido (Cardinal) on Aug 08, 2011 at 01:38 UTC

    I actually liked this question a lot as it got me thinking of various approaches. First I started tinkering with plain old binary and hex math, the >> operator, counting number of bits needed to represent any unsigned integer, etc. It took me back to high school Comp Sci classes.

    A quick diversion: If you have a given resolution (say four bits, which is what is needed to represent one hex digit, as in the OP's example), you can calculate number of bits needed to represent any positive integer like this:

    sub bits_needed { my ( $unsigned, $resolution ) = @_; my $bits_needed = floor( log2( $unsigned ) ) + 1; $bits_needed += $resolution - $bits_needed % $resolution if defined $resolution; return $bits_needed; }

    Of course for that we need floor(), so we may use POSIX, and we also need log2() which is implemented as:

    sub log2 { my $n = shift; return log($n)/log(2); }

    But that's just a tangent that the original question drove me toward as I explored, and has nothing to do with the solution I ended up playing with.

    We already had a pack and unpack solution, so I wanted to see what else is out there.

    Back to the point: Introducing the CPAN. I found Bit::Vector. What a cool module! It makes bit twiddling simple.

    Here's an example:

    use strict; use warnings; use Bit::Vector; use Text::Template; use v5.12; my $orig_hex = "6bf"; my ( $reverse, $details ) = hex_reverse_bitwise( $orig_hex, 12 ); print Text::Template->fill_this_in( do{ undef $/; <DATA> }, HASH => $details, ); # Return bitwise reversed hex digits in scalar context. # In list context, return reversed hex digits plus a hashref # containing more detailed analysis. sub hex_reverse_bitwise { my ( $start, $bit_size ) = @_; my $orig_vec = Bit::Vector->new_Hex( $bit_size, $orig_hex ); my $rev_vec = Bit::Vector->new( $bit_size ); $rev_vec->Reverse( $orig_vec ); my $reversed = $rev_vec->to_Hex; return( $reversed, wantarray() ? { orig_hex => $orig_hex, orig_bits => $orig_vec->to_Bin, reversed_bits => $rev_vec->to_Bin, new_hex => $reversed, } : () ); } __DATA__ Given the hex digits '{lc $orig_hex}' with a bit representation of '{$orig_bits}', reversing the bits to '{$reversed_bits}' we get a hex representation of '{lc $new_hex}'.

    The output is:

    Given the hex digits '6bf' with a bit representation of '011010111111', reversing the bits to '111111010110' we get a hex representation of 'fd6'.

    I had a little fun with Text::Template while I was at it. It's hard to beat the raw throughput of pack and unpack, but the Bit::Vector approach abstracts away some of the complexity.

    Thanks for the motivation to tinker.


    Dave

Re: LSB to MSB
by Anonymous Monk on Aug 07, 2011 at 06:29 UTC

    Have a hex value of 6bf 0110 | 1011 | 1111

    What you really have is

    6b f0

    I've looked at "pack/unpack" but cannot figure it out.

    Show your efforts. Usually, pack/unpack aren't used for flipping bits, you use & or | for that, see perlop

    Your title hints what you really are talking about is

    $ perl -le " print unpack 'H*', pack 'h*', '6bf'; b60f
    or
    $ perl -le " print join ' ', split /(....)/, unpack 'b*', pack 'h*', ' +6bf'; 0110 1101 1111 0000 $ perl -le " print join ' ', split /(....)/, unpack 'B*', pack 'h*', ' +6bf'; 1011 0110 0000 1111
      What you really have is
      6b f0

      Why?  Normally, you can leave off leading zeros, i.e. 0x6bf is the same as 0x06bf or 0x000006bf.

      0x6bf0 is a different value, though:

      $ perl -le 'print 0x6bf' 1727 $ perl -le 'print 0x6bf0' 27632

        Why?...

        Thanks

        You can see from my code examples why I thought so, pack doesn't assume leading 0, and I did not make the integer connection