Converting hex string to 32 bit signed integer

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • whirly
    New Member
    • Aug 2007
    • 5

    Converting hex string to 32 bit signed integer

    I have a hex value FFFFFFCE that actually represents -50. When I simply use hex function to convert the above value to an integer, I get 4294967246. That means that integer overflow took place. How do I handle such cases, so that conversion will be correct?
  • KevinADC
    Recognized Expert Specialist
    • Jan 2007
    • 4092

    #2
    I thought 50 in hex is 32? (16x3+2)

    Comment

    • whirly
      New Member
      • Aug 2007
      • 5

      #3
      thanks for your reply. Actually, it is negative 50. I know that if I do the following: $t = hex('ffffffce') & hex('7ffffffff' ); $t = $t - hex('7fffffff') - 1;, I get the correct value of negative 50. But this is clunky.

      Comment

      • KevinADC
        Recognized Expert Specialist
        • Jan 2007
        • 4092

        #4
        I'm lost......... :(

        Comment

        • whirly
          New Member
          • Aug 2007
          • 5

          #5
          Sorry. Let me try to clarify. I am trying to convert 8-character hex values to their 32-bit integer representation. The problem arises when a hex string starts with FFFF (ex. FFFFFFCE). I know that the real answer once the conversion is done is "-50" for "FFFFFFCE". You can check it by entering "-50" into any calculator that does conversions, and you will see that the hex value for it is "FFFFFFCE". But if you enter "FFFFFFCE" first and try to convert it to an integer, you will get "4294967246 ", which indicates overflow. My current solution is to subtract the maxint value (FFFFFFFF) from the given value (FFFFFFCE) and to subtract 1 from the result, which will yield the correct value of "-50". I don' t know if that is the best way and also if there are any other gotchas. I would imagine underflow will also present problems.

          Comment

          • numberwhun
            Recognized Expert Moderator Specialist
            • May 2007
            • 3467

            #6
            Have you tried using the Data::Translate module from cpan? It looks like it does conversions like the one you are looking to do.

            Regards,

            Jeff

            Comment

            • whirly
              New Member
              • Aug 2007
              • 5

              #7
              Thank you, Jeff. I will check it out.

              Comment

              • miller
                Recognized Expert Top Contributor
                • Oct 2006
                • 1086

                #8
                Originally posted by whirly
                Sorry. Let me try to clarify. I am trying to convert 8-character hex values to their 32-bit integer representation.
                Actually, what you are trying to do is convert an 8 character hex string to a 32-bit SIGNED integer, at least according to the specification from Java or C. The problem you have is that there is no such thing as a strictly 32-bit integer in perl, so you must code the rules yourself or use a module as Jeff suggested.

                Fortunately, the rules are fairly simple. But let's start with unsigned first:
                unsigned int
                Dec: 0 to 4_294_967_295 (2^32-1)
                Hex Representation: 0x00000000 to 0xFFFFFFFF

                As you can see, straight forward enough. And the hex translation can be handled directly with the hex function and sprintf.

                Signed integers are a little harder. The positive range is handled easily enough. However, the negative range is indicated by the 32nd bit, and the values are stored opposite of the positive range. This made arithmetic simpler back in the "old days" I suspect.

                signed int
                Dec: (-1 * 2 ^ 31) -2_147_483_648 to 2_147_483_647 (2 ^ 31 - 1)
                hex positive: 0x00000000 to 0x7FFFFFFF
                hex negative: 0xFFFFFFFF to 0x80000000

                The easiest way to code your own translation function would be to rely on a little bit arithmetic:

                [CODE=perl]
                print hexstr_to_signe d32int('FFFFFFC E'), "\n"; # Outputs -50
                print signed32int_to_ hexstr(-50), "\n"; # Outputs ffffffce

                sub hexstr_to_signe d32int {
                my ($hexstr) = @_;
                die "Invalid hex string: $hexstr"
                if $hexstr !~ /^[0-9A-Fa-f]{1,8}$/;

                my $num = hex($hexstr);
                return $num >> 31 ? $num - 2 ** 32 : $num;
                }

                sub signed32int_to_ hexstr {
                my ($num) = @_;
                die "Number outside of signed 32-bit range: $num"
                if $num > 2_147_483_647 or $num < -2_147_483_648;

                my $unsigned = $num < 0 ? 2 ** 32 + $num : $num;
                return sprintf "%x", $unsigned;
                }
                [/CODE]

                If you wanted capital hex strings, just change %x to %X

                - Miller

                Comment

                • whirly
                  New Member
                  • Aug 2007
                  • 5

                  #9
                  Thank you so much!!!

                  Comment

                  • Phatfingers
                    New Member
                    • Jul 2008
                    • 2

                    #10
                    Really great answer! Your thorough explanation helped me with a loosely related issue in creating a hashing function compatible with ones we use in Java and C. Perl had the binary result intact, but just needed a little adjustment to represent it as an unsigned integer value. Much appreciated.

                    Originally posted by miller
                    The problem you have is that there is no such thing as a strictly 32-bit integer in perl, so you must code the rules yourself or use a module as Jeff suggested.
                    ...
                    [CODE=perl]
                    return $num >> 31 ? $num - 2 ** 32 : $num;
                    [/CODE]
                    - Miller

                    Comment

                    Working...