我最近正在研究Java中的一些问题,但我提出了两个问题。
1)首先,我想到了翻转数字中所有位的问题。
我找到了这个解决方案:
public class Solution {
public int flipAllBits(int num) {
int mask = (1 << (int)Math.floor(Math.log(num)/Math.log(2))+1) - 1;
return num ^ mask;
}
}
但是当k = 32位时会发生什么? 1可以换挡33次吗?
我从代码中理解的内容(尽管它没有意义),掩码是0111111.(31 1).... 1而不是32 1,正如有人所期望的那样。因此,当num是一个非常大的数字时,这将失败。
2)另一个问题我在确定什么时候是2s补码中的位序列或只是正常的位序列。例如,我读到翻转时的1010是0110,即-10,但也是6.哪一个是它,我们怎么知道?
感谢。
答案 0 :(得分:1)
1)不需要Math对象调用。在Java(或C)中翻转任何序数类型的所有位不是算术运算。这是一个按位操作。使用&#39; ^&#39;运算符,只需使用1-作为操作数就可以工作,无论C / C ++中的sizeof int或带有序数类型作为参数T的Java模板。代字号&#39;〜&#39;运营商是另一种选择。
T i = 0xf0f0f0f0;
System.out.println(T.toHexString(i));
i ^= -1;
System.out.println(T.toHexString(i));
i = ~ i;
System.out.println(T.toHexString(i));
2)由于整个整数范围映射到2恭维变换中的整个整数范围,因此无法检测数字是否是2的补码,除非有人知道可以计算2的补码的数字范围,两组(之前和之后)是互斥的。
答案 1 :(得分:0)
掩码计算是相当难以理解的,我猜它(尝试,因为你提到它错了)制作一个掩码,包括最高设置位。这对于翻转所有位是否有用&#34;是另一个可能的讨论点,至少对我来说,&#34;所有位&#34;表示所有32个,而不是取决于值的某个数字。但如果这就是你想要的那么,那就是你想要的。特别是与第二个问题相结合,这对我来说似乎是一个错误,所以你从一开始就实施了错误的东西 - 看到底部附近。
无论如何,掩码可以用一些相当不错的bitmath生成,这不会对可能的边缘情况产生任何疑问(例如Math.log(0)
可能是坏的,而k = 32对应的负数也可能是坏的放入日志):
int m = num | (num >> 16);
m |= m >> 8;
m |= m >> 4;
m |= m >> 2;
m |= m >> 1;
return num ^ m;
请注意,此函数具有奇数属性,它几乎总是返回一个无符号 - 较小的数字,除了为0.它翻转位以使名称不完全错误,但是flipAllBits(flipAllBits(x)) != x
(通常),而这个名字表明它应该是一个内卷。
关于第二个问题,没有什么可以确定的。两个补码是可以解释位向量的方案 - 任何位向量。所以它真的是你做出的选择;以这种方式或其他方式解释给定的位向量。在Java中,&#34;默认&#34;解释是两个补充(例如toString将根据它的两个补充意义解释它来打印一个int),但是你不必同意它,你可以(小心)将int
视为无符号,或者作为一组布尔值,或将几个位域组合在一起等等。
如果你想反转 all 这些位,但是常常会误认为int中的位数是可变的(因此你需要计算一个覆盖&#34的掩码) ;所有位&#34;),我有一些好消息,因为反转所有位是 lot 更容易:
return ~num;
如果你正在阅读&#34;反转所有位&#34;在两个补码的上下文中,它具有上述含义,因此所有位,包括最高设置位的剩余部分。