如何在 Java 中执行无符号到有符号的转换?

2022-01-13 00:00:00 type-conversion signed java

假设我从输入设备读取了这些字节:6F D4 06 40".该数字是 MilliArcSeconds 格式的经度读数.最高位(0x80000000)基本上总是零,并且在这个问题中被忽略.

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.

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

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

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

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. 如果值 &0x40000000 那么它实际上是负数,需要转换它
  2. 如果是负数,就去掉上面的位,然后用剩下的位做点什么……

所以我可以判断它是否是一个负数,但为了知道负数是什么值,我必须对剩余的位做一些事情 - 一个人的恭维?我如何在 Java 中做到这一点?

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?

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

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

谢谢!

推荐答案

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

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

无符号输入:0x6FD40640 == 1876166208

二的补码整数是一个整数,其中 -1 设置了所有位,并且较低的负数从那里向下计数.第一位仍然充当符号位.

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

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

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;

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

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.

一个补码数字表示形式是第一位是专用符号位,其余位表示幅度.-100 的低位将与 100 的低位相同:

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

如果低 31 位表示一个一个补码整数(即一个符号位后跟 30 位表示一个无符号量值),那么需要将其转换为二进制补码,以便 Java 提取正确的值.为此,您只需提取低 30 位并乘以 -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;
}

您在问题的评论中说,在转换为度数(除以 3600000)后,您会得到 -75.36 左右.当我将 -271317440 除以 3600000 时,我得到 -75.36595555555556,所以我猜你的输入格式是二进制补码,所以我的第一个原始答案是正确的.

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.

相关文章