按位否定会产生意外结果
我试图在java中编写一个按位计算器,你可以输入一个表达式,如~101,但是当我运行这段代码时它会返回10
import java.util.Scanner; public class Test { public static void main(String[] args) { Integer a = Integer.valueOf("101", 2); System.out.println(Integer.toString(~a,2)); } }
它输出-110为什么?
你假设101是三位长。 Java不支持可变长度位操作,它在整个int
位操作,因此~
将not
32位长“101”。
—被问到“我怎么能解决这个问题后编辑?” —
这是一个非常好的问题,但答案是“你不能”和“你可以通过不同方式实现同样的事情”。
您无法修复~
运算符,因为它执行的操作。 这有点像要求修复+
只添加1的位置。 只是不会发生。
你可以实现所需的操作,但是你需要更多的“东西”来实现它。 首先,你必须有一些东西 (另一个int)来指定感兴趣的位 。 这通常称为位掩码 。
int mask = 0x00000007; // just the last 3 bits. int masked_inverse = (~value) & mask;
注意,我们所做的实际上是反转32位,然后将这些位中的29位归零; 因为,它们在面具中被设置为零,这意味着“我们不关心它们”。 这也可以想象为利用&
运算符,我们说“如果设置,我们关心它,设置它”。
现在你仍然有32位,但只有低3位将被反转。 如果你想要一个3位数据结构,那么这是一个不同的故事。 Java(和大多数语言)只是不直接支持这些东西。 因此,您可能想要在Java中添加另一种类型来支持它。 Java通过类机制添加类型,但内置类型不可更改。 这意味着您可以编写一个表示3位数据结构的类,但它必须在内部处理整数为32位字段。
幸运的是,有人已经这样做了。 它是标准Java库的一部分, 称为BitSet
。
BitSet threeBits = new BitSet(3); threeBits.set(2); // set bit index 2 threeBits.set(0); // set bit index 0 threeBits.flip(0,3);
然而,由于Java中类/对象系统的约束,这种位操作对它们有不同的感觉,这是因为将类定义为在Java中添加新类型的唯一方法 。
如果a = ...0000101 (bin) = 5 (dec)
~a = ~...0000101(bin) = ...1111010(bin)
而Java使用“ 二进制补码 ”forms来表示负数
~a = -6 (dec)
现在负数的Integer.toBinaryString(number)
和Integer.toString(number, 2)
之间的区别是
-
toBinaryString
以“ Two’s complement ”forms返回String但是 -
toString(number, 2)
计算二进制forms,如同数字为正,如果参数为负,则添加“减号”标记。
所以toString(number, 2)
为~a = -6
会
- 计算
6
– >0000110
二进制值, - 修剪前导零 – >
110
, - 添加减号 – >
-110
。
整数101实际上表示为00000000000000000000000000000101
否定这个你得到11111111111111111111111111111010
– 这是-6
。
toString()方法将其参数解释为有符号值。
要演示二进制操作,最好使用Integer.toBinaryString()
。 它将其参数解释为无符号,因此~101输出为1111111111111111111111111111111010。
如果您想要更少的输出位,可以用&屏蔽结果。
只是详细说明Edwin的答案 – 如果你想创建一个可变长度的掩码来开发感兴趣的部分,你可能需要一些辅助函数:
/** * Negate a number, specifying the bits of interest. * * Negating 52 with an interest of 6 would result in 11 (from 110100 to 001011). * Negating 0 with an interest of 32 would result in -1 (equivalent to ~0). * * @param number the number to negate. * @param bitsOfInterest the bits we're interested in limiting ourself to (32 maximum). * @return the negated number. */ public int negate(int number, int bitsOfInterest) { int negated = ~number; int mask = ~0 >>> (32 - bitsOfInterest); logger.info("Mask for negation is [" + Integer.toBinaryString(mask) + "]"); return negated & mask; } /** * Negate a number, assuming we're interesting in negation of all 31 bits (exluding the sign). * * Negating 32 in this case would result in ({@link Integer#MAX_VALUE} - 32). * * @param number the number to negate. * @return the negated number. */ public int negate(int number) { return negate(number, 31); }