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

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

stylechief
Guest
Posts: n/a

 04-08-2005
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

Joe Smith
Guest
Posts: n/a

 04-08-2005
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

stylechief
Guest
Posts: n/a

 04-08-2005

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

stylechief
Guest
Posts: n/a

 04-11-2005
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";
\$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.

Guest
Posts: n/a

 04-12-2005
stylechief <(E-Mail Removed)> 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.

--
http://www.velocityreviews.com/forums/(E-Mail Removed) Perl programming
Fort Worth, Texas

Joe Smith
Guest
Posts: n/a

 04-12-2005
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";
> \$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

\$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

stylechief
Guest
Posts: n/a

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

open (BINFILE, "<000332") || die "Cant open: \$!\n";

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