按位否定会产生意外结果

我试图在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

  1. 计算6 – > 0000110二进制值,
  2. 修剪前导零 – > 110
  3. 添加减号 – > -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); }