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.
|