问题是要反转32位无符号整数的位(因为Java没有我们长时间使用的无符号整数)。
以下是我的代码的两个版本。我有两个问题:
(1)为什么我的第一和第二个解决方案不会返回相同的值(正确与否)
(2)我的第一和第二个解决方案在没有得到正确答案时出错了
//reverse(3) returns 0
public static long reverse(long a) {
long numBits = 32;
long finalResult = 0;
for(int i = 0; i < numBits; i++){
long ithBit = a & (1 << i);
finalResult = finalResult + ithBit * (1 << (numBits - i - 1));
}
return finalResult;
}
第二版:
//reverse(3) return 4294967296
public static long reverse(long a) {
long numBits = 32L;
long finalResult = 0L;
for(long i = 0L; i < numBits; i++){
long ithBit = a & (1L << i);
finalResult = finalResult + ithBit * (1L << (numBits - i - 1L));
}
return finalResult;
}
此代码(解决方案)返回正确答案:
//reverse(3) returns 3221225472
public static long reverse(long A) {
long rev = 0;
for (int i = 0; i < 32; i++) {
rev <<= 1;
if ((A & (1 << i)) != 0)
rev |= 1;
}
return rev;
}
谢谢!
答案 0 :(得分:1)
因为Java没有无符号整数,所以我们使用很长时间。
这通常是不必要的,因为除了除法和比较之外的所有算术运算都会导致java使用two's complement representation中的无符号和有符号数的相同位模式。对于后两个操作Integer.divideUnsigned(int, int)
和Integer.compareUnsigned(int, int)
可用。
问题是要反转32位无符号整数的位
有Integer.reverse(int)
Relevant docs,强烈建议花一些时间阅读它们。
答案 1 :(得分:0)
在这两个版本中,您都遇到了逻辑问题:
ithBit * (1 << (numBits - i - 1));
因为两个数字相乘于设置的第31位(第32位)的相同位模式。
在版本1中,如果设置了位-2^31
,则添加的数量为0
,因为您正在对int
进行位移,因此位移结果为int
表示-2^31
表示高位被设置,或2^31
表示每个其他位,这可能是由于自动转换为结果的长度。您有两种位(0
和非0
),因此结果为零。
版本2存在同样的问题,但没有消极的int
问题,因为您正在移动long
。每个1位将添加2^31
。数字3
设置了2位,因此您的结果为2 * 2^31
(或2^32
)4294967296
。
要修复您的逻辑,请使用版本2,但请将乘以ithBit
。
答案 2 :(得分:0)
让您在迭代时查看您的值。为了澄清,我们将查看中间值,因此我们将代码更改为:
int n = (1 << (numBits - i - 1));
long m = ithBit * n;
finalResult = finalResult + m;
您的起始值是3:
a = 0000 0000 0000 0000 0000 0000 0000 0011
第一次循环迭代(i = 0):
ithBit = 00000000 00000000 00000000 00000001
n = 11111111 11111111 11111111 11111111 10000000 00000000 00000000 00000000
m = 11111111 11111111 11111111 11111111 10000000 00000000 00000000 00000000
finalResult = 11111111 11111111 11111111 11111111 10000000 00000000 00000000 00000000
第二次循环迭代(i = 1):
ithBit = 00000000 00000000 00000000 00000010
n = 01000000 00000000 00000000 00000000
m = 10000000 00000000 00000000 00000000
finalResult = 00000000 00000000 00000000 00000000
如您所见,第一个迭代设置n = 1 << 31
,即-2147483648。在您的第二个版本中,您执行n = 1L << 31
,即2147483648,这就是为什么您的两个版本会产生不同结果的原因。
正如您所看到的,您绝对不想要m = ithBit * n
部分。
通过自己打印来查看您的号码,然后您就可以了解它。
顺便说一下,这是我的版本。如果您无法理解它,请尝试打印中间值以查看正在进行的操作。public static long reverse4(long a) {
long rev = 0;
for (int i = 0; i < 32; i++, a >>= 1)
rev = (rev << 1) | (a & 1);
return rev;
}
答案 3 :(得分:0)
你的两个例子的问题是“第i位”不是0或1而是掩盖了。在任何一种情况下,第31位都是0x8000_0000。在第一种情况下,这是一个int,所以它是负的,当转换为long时它保持为负。在第二种情况下,它已经很长,所以它保持正面。要修复它以实现您的预期,请执行以下操作:
ithBit = (a >>> i) & 1;
顺便说一句,使用long
是愚蠢的;只要您了解Java中有两种类型的转换,unsigned vs. signed没有任何区别。
顺便说一下,这三个例子都很糟糕。如果你正在做位操作,你想要速度,对吗? (为什么还要打扰位?)
这是如何正确行事(不是我的,从http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits偷来的):
a = ((a >>> 1) & 0x55555555) | ((a & 0x55555555) << 1);
a = ((a >>> 2) & 0x33333333) | ((a & 0x33333333) << 2);
a = ((a >>> 4) & 0x0F0F0F0F) | ((a & 0x0F0F0F0F) << 4);
a = ((a >>> 8) & 0x00FF00FF) | ((a & 0x00FF00FF) << 8);
a = ( a >>> 16 ) | ( a << 16);