Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to perform unsigned to signed conversion in Java?

Say I read these bytes: "6F D4 06 40" from an input device. The number is a longitude reading in MilliArcSeconds format. The top bit (0x80000000) is basically always zero and is ignored for this question.

I can easily convert the bytes to an unsigned integer: 1876166208

But how do I convert that unsigned value into its final form of 31-bit signed-integer?

So far all I've come up with is:

  1. if value & 0x40000000 then it's actually negative, need to convert it
  2. If it's negative, strip the top bit and do something with the remaining bits...

So I can tell if it's a negative number, but in order to know what value the negative number is, I have to do something with the remaining bits - a one's compliment? How do I do that in Java?

Another way to put the question is, how do I convert an unsigned integer into a 31-bit signed integer in Java?

Thank you!

like image 971
Brad Hein Avatar asked Oct 14 '10 16:10

Brad Hein


1 Answers

The answer depends on what the lower 31 bits of your input are meant to represent.

int input = 0x6FD40640 & 0x7FFFFFFF; //strip top bit; only here for clarity

Unsigned input: 0x6FD40640 == 1876166208

Two's complement (desired output: -271317440)

A two's complement integer is one where -1 has all bits set, and lower negatives number count down from there. The first bit still acts as a sign bit.

1000 -> -8
1001 -> -7
...
1110 -> -2
1111 -> -1
0000 ->  0
0001 ->  1

If the lower 31 bits represent a two's complement integer, then I think you should just be able to do this:

input = (input << 1) >> 1;

That's because Java stores integers in two's complement internally: all we do is shift left and then shift back right (signed) so that the sign bit is picked up and the integer goes from 31 bits to 32 bits.

One's complement (desired output: -802424384)

A one's complement number representation is one where the first bit is a dedicated sign bit, and the remaining bits represent the magnitude. The lower bits of -100 will be the same as the lower bits of 100:

 1111 -> -7
 1110 -> -6
 ...
 1001 -> -1
 1000 -> -0 (anomoly)
 0000 ->  0
 0001 ->  1

If the lower 31 bits represent a one's complement integer (that is, a sign bit followed by 30 bits representing an unsigned magnitude), then you need to convert it into two's complement so that Java extracts the value properly. To do this you just need to extract the lower 30 bits and multiply by -1:

if ( input & 0x40000000 ) {
   input = (input & 0x3FFFFFFF) * -1;
}

You said in the question's comments that after converting to degrees (dividing by 3600000) you get around -75.36. When I divide -271317440 by 3600000 I get -75.36595555555556, so I'm guessing your input format is two's complement, so my first and original answer was correct.

like image 103
Mark Peters Avatar answered Nov 07 '22 05:11

Mark Peters