如何在Java中执行unsigned to signed转换?

时间:2010-10-14 16:18:08

标签: java type-conversion signed

假设我从输入设备读取这些字节:“6F D4 06 40”。该数字是MilliArcSeconds格式的经度读数。顶部位(0x80000000)基本上始终为零,并且在此问题中被忽略。

我可以轻松地将字节转换为无符号整数:1876166208

但是如何将无符号值转换为31位有符号整数的最终形式?

到目前为止,我想出的只有:

  1. 如果价值& 0x40000000然后它实际上是负数,需要转换它
  2. 如果是负数,请删除顶部位并对其余位执行某些操作...
  3. 所以我可以判断它是否为负数,但为了知道负数是多少,我必须对其余的位做些什么 - 一个人的恭维?我如何用Java做到这一点?

    提出问题的另一种方法是,如何在Java中将无符号整数转换为31位有符号整数?

    谢谢!

2 个答案:

答案 0 :(得分:4)

答案取决于输入的低31位代表什么。

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

无符号输入:0x6FD40640 == 1876166208

二进制补码(所需输出:-271317440)

二进制补码整数是-1,其中-1设置了所有位,而较低的负数数字从那里开始倒数。第一位仍然作为符号位。

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

如果低31位表示二进制补码整数,那么我认为你应该能够做到这一点:

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

这是因为Java在内部以二进制补码存储整数:我们所做的只是向左移位然后向右移位(有符号),以便拾取符号位,整数从31位变为32位。

一个补码(所需输出:-802424384)

1的补码数表示是第一位是专用符号位的表示,其余位表示幅度。 -100的低位与100的低位相同:

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

如果低31位表示 1的补码整数(即符号位后跟30位表示无符号幅度),则需要将其转换为二进制补码,以便Java提取价值得当。要做到这一点,你只需要提取低30位并乘以-1:

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

你在问题​​的评论中说过,在转换为学位(除以3600000)后,你得到-75.36左右。 当我将-271317440除以3600000时,我得到-75.36595555555556 ,所以我猜你的输入格式是两个补码,所以我的第一个和原始答案是正确的。

答案 1 :(得分:0)

读取带符号的无符号整数是确定是否设置了最高有效位(负标志)的问题,如果是,则翻转该数字的所有位(从而清除最高有效位,并将数字切换为负面表示。在执行上述过程时,您还必须记下结果数字为负数的事实。

// 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);