Perl function for negative integers using the 2's complement in hex?

S

stylechief

I cannot seem to find a Perl function that will return the 2's
complement of a negative integer represented in hex.
For example:
ffbe8e should return -16754, not 16760462

hex() works fine for positive integers but not here
pack/unpack don't seem to want to produce anything negative (just 0)

I imagine that there is a 'brute force' method, but it seems that there
should be an eloquent function that speaks in 2's complement . . . .

Thanks,
Liam
 
J

Joe Smith

stylechief said:
I cannot seem to find a Perl function that will return the 2's
complement of a negative integer represented in hex.
For example:
ffbe8e should return -16754, not 16760462

You have to remember that 32-bit integers are represented by
eight hex digits, not six.

linux% perl -le 'printf "%d %d\n",0xffbe8e,0xffffbe8e'
16760462 -16754

If you have a 24-bit number you will need to sign-extend the
most significant bit in order to produce a 32-bit number.

linux% cat temp
$bits_24 = hex("ffbe8e");
$bits_32 = $bits_24 | (($bits_24 & 0x800000) ? 0xff000000 : 0);
printf "%d %.0f\n", $bits_32, $bits_32;

linux% perl temp
-16754 4294950542
 
S

stylechief

That works like a charm when one can explicitly pass a hex number like
the above example. However, for whatever reason, when one attempts to
read from a binary file and use unpack() to deliver the hex numbers,
one gets:
Argument "ffbe8e" isn't numeric in pack at E:\Test\bif.plx line 5.

code:
open (BINARYFILE, "<000332") || die "Cant open: $!\n";
while(read(BINARYFILE, $data, 3)){
$data= unpack 'H*',$data;
print unpack 'i',pack 'i',$data;
print "\n";
}
close (BINARYFILE) || die"Cant close: $!\n";

It *is* unpacking to a 24 bit hex number, but fails to see this number
as numeric. It gets "stringified" somehow.
 
J

Joe Smith

stylechief said:
That works like a charm when one can explicitly pass a hex number like
the above example. However, for whatever reason, when one attempts to
read from a binary file and use unpack() to deliver the hex numbers,
one gets:
Argument "ffbe8e" isn't numeric in pack at E:\Test\bif.plx line 5.

code:
open (BINARYFILE, "<000332") || die "Cant open: $!\n";
while(read(BINARYFILE, $data, 3)){
$data= unpack 'H*',$data;
print unpack 'i',pack 'i',$data;
print "\n";
}
close (BINARYFILE) || die"Cant close: $!\n";

It *is* unpacking to a 24 bit hex number,


No, it is unpacking to a six-character string of hexadecimal digits.
The phrase "24 bit hex number" is meaningless, what you've got is
a 24-bit number expressed as a string of hexadecimal digits.
but fails to see this number as numeric. It gets "stringified" somehow.

Using 'H' with unpack() returns a string, not a number.
The string of hexadecimal digits needs to go through the hex() function
in order to be numeric.

$hexdata = unpack 'H*',$data;
$integer = hex $hexdata;
print unpack 'i', pack 'i',$integer;

or

read(BINARYFILE, $three_bytes, 3);
$four_bytes = '\x00' . $three_bytes;
$integer = unpack 'i',$four_bytes;

or

$sign_extend = ($three_bytes & "\x80\x00\x00") ? "\xff" : "\x00";
$four_bytes = $sign_extend . $three_bytes;

(Obviously, little-endian machines and big-endian ones need to
handle those last two differently.)

-Joe
 
S

stylechief

Thanks to all for your time and consideration. The solution that I was
seeking:

open (BINFILE, "<000332") || die "Cant open: $!\n";
while(read(BINFILE, $data, 3)){

$data=hex(unpack 'H*',$data);
if ($data & 0x800000) {$data |= 0xff000000};
printf "%d \n", $data;

}
close (BINFILE) || die "Cant close: $!\n";

Unless there is yet a more efficient method . . . .
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top