Java中的位操作 - 2s补充和翻转位

时间:2017-01-31 19:33:54

标签: java bit-manipulation

我最近正在研究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.哪一个是它,我们怎么知道?

感谢。

2 个答案:

答案 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;在两个补码的上下文中,它具有上述含义,因此所有位,包括最高设置位的剩余部分。