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

发布于 2024-09-27 07:55:11 字数 427 浏览 6 评论 0原文

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

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

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

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

  1. if value & 0x40000000 那么它实际上是负数,需要转换它
  2. 如果它是负数,则去掉顶部位并对剩余位执行一些操作...

所以我可以判断它是否是负数,但为了知道负数是什么值,我必须用剩下的部分做点什么——一个人的恭维?我该如何在 Java 中做到这一点?

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

谢谢你!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

哆兒滾 2024-10-04 07:55:11

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

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

无符号输入:0x6FD40640 == 1876166208

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

二进制补码整数是其中 -1 已设置所有位且较低负数倒数的整数从那里。第一个位仍然充当符号位。

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

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

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

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

补码(所需输出:-802424384)

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

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

如果低 31 位表示一个补码整数(即符号位后跟表示无符号数值的 30 位) ,那么您需要将其转换为二进制补码,以便 Java 正确提取该值。为此,您只需提取较低的 30 位并乘以 -1:

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

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

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.

|煩躁 2024-10-04 07:55:11

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

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

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文