Duke Leto
Duke Leto

Reputation: 215

How to isolate leftmost bytes in integer

This has to be done in Perl:

I have integers on the order of e.g. 30_146_890_129 and 17_181_116_691 and 21_478_705_663.

These are supposedly made up of 6 bytes, where:

I want to isolate what value a is. How can I do this in Perl?

I've tried using the >> operator:

perl -e '$a = 330971351478 >> 16; print "$a\n";'
5050222
perl -e '$a = 17181116691 >> 16; print "$a\n";'
262163

But these numbers are not on the order of what I am expecting, more like 0-1000.

Bonus if I can also get values b and c but I don't really need those.

Thanks!

Upvotes: 2

Views: 300

Answers (2)

ikegami
ikegami

Reputation: 385849

If you have 6 bytes, you don't need to convert them to a number first. You can use one the following depending on the order of the bytes: (Uppercase represents the most significant byte.)

my ($num_c, $num_b, $num_a) = unpack('nnn', "\xCC\xcc\xBB\xbb\xAA\xaa");
my ($num_a, $num_b, $num_c) = unpack('nnn', "\xAA\xaa\xBB\xbb\xAA\xaa");
my ($num_c, $num_b, $num_a) = unpack('vvv', "\xcc\xCC\xbb\xBB\xaa\xAA");
my ($num_a, $num_b, $num_c) = unpack('vvv', "\xaa\xAA\xbb\xBB\xcc\xCC");

If you are indeed provided with a number 0xCCccBBbbAAaa), you can convert it to bytes then extract the numbers you want from it as follows:

my ($num_c, $num_b, $num_a) = unpack('xxnnn', pack('Q>', $num));

Alternatively, you could also use an arithmetic approach like you attempted.

my $num_a =   $num         & 0xFFFF;
my $num_b = ( $num >> 16 ) & 0xFFFF;
my $num_c =   $num >> 32;

While the previous two solutions required a Perl built to use 64-bit integers, the following will work with any build of Perl:

my $num_a =      $num           % 2**16;
my $num_b =    ( $num / 2**16 ) % 2**16;
my $num_c = int( $num / 2**32 );

Let's look at ( $num >> 16 ) & 0xFFFF in detail.

Original number: 0x0000CCccBBbbAAaa
After shifting:  0x00000000CCccBBbb
After masking:   0x000000000000BBbb

Upvotes: 4

Steffen Ullrich
Steffen Ullrich

Reputation: 123320

number >> 16 returns number shifted by 16 bit and not the shifted bits as you seem to assume. To get the last 16 bit you might for example use number % 2**16 or number & 0xffff. To get to b and c you can just shift before getting the last 16 bits, i.e.

$a = $number & 0xffff;
$b = ($number >> 16) & 0xffff;
$c = ($number >> 32) & 0xffff;

Upvotes: 5

Related Questions