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

Discussion in 'Perl Misc' started by stylechief, Apr 8, 2005.

1. ### stylechiefGuest

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

stylechief, Apr 8, 2005

2. ### Joe SmithGuest

Re: Perl function for negative integers using the 2's complementin hex?

stylechief wrote:
> 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

Joe Smith, Apr 8, 2005

3. ### stylechiefGuest

Thanks for the help, guys. It is a 24 bit number I'm working with.

stylechief, Apr 8, 2005
4. ### stylechiefGuest

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.

stylechief, Apr 12, 2005
5. ### Tad McClellanGuest

stylechief <> wrote:

> That works like a charm

What does?

> when one can explicitly pass a hex number like
> the above example.

What example above?

Please compose followups the normal way and quote some context.

--
Tad McClellan SGML consulting
Perl programming
Fort Worth, Texas

Tad McClellan, Apr 12, 2005
6. ### Joe SmithGuest

Re: Perl function for negative integers using the 2's complementin hex?

stylechief wrote:
> 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

Joe Smith, Apr 12, 2005
7. ### stylechiefGuest

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

stylechief, Apr 12, 2005

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.