How to perform unsigned to signed conversion in Java?

前端 未结 2 1111
盖世英雄少女心
盖世英雄少女心 2021-01-02 22:10

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

相关标签:
2条回答
  • 2021-01-02 22:58

    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.

    0 讨论(0)
  • 2021-01-02 23:04

    Reading an unsigned integer as signed is a matter of identifying whether the most significant bit (negative flag) is set, and if so, flip all bits of the number (thus clearing the most significant bit, and switching the number to its negative representation. When performing the aforementioned process you must also make note of the fact that the resultant number is a negative.

    // Convert the hex bytes to an unsigned integer
    long MAS = Integer.ValueOf("6F D4 06 40".replace (" ",""),16);
    boolean isLongitudeNegative = false;
    
    // Is the negative-bit set? If so, strip it and toggle all bits.
    if (MAS & 0x40000000 > 0) {
        // then it's negative, so strip the negative bit and flip all the other bits
        MAS ^= 0xFFFFFFFF;
        // Throw away the unused bit.
        MAS &= 0x7FFFFFFF;
        isLongitudeNegative = true;
    }
    
    // Now convert from MAS to degrees minutes seconds
    String DMS = convertMASToDMS(isLongitudeNegative,MAS);
    
    0 讨论(0)
提交回复
热议问题