Java BigInteger的按位NOT为负

时间:2017-04-03 05:22:09

标签: java math bit-manipulation biginteger

我试图在Java中使用128位BigInteger进行逐位执行。我有一个128位的数字,其前64位设置为1,最后64位设置为0(我正在使用IPv6掩码)。

BigInteger b = new BigInteger(2).pow(64).subtract(BigInteger.ONE).shiftLeft(64);
System.out.println(b.toString(2));

如果我使用base 2输出它,则会产生以下结果:

11111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000

我试图使用按位来翻转/反转所有位。

System.out.println(b.not().toString(2));

根据我的理解而不是,我希望所有的1都改为0,所有的0都改为1,但我得到以下内容:

-11111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000

这似乎也符合not()函数的文档:

  

当且仅当此BigInteger为非负

时,此方法才返回负值

这是循环所有128位而不是逐位执行按位的情况吗?

更新的 如果我试着解释一下我想要实现的目的,那么它可能会有所帮助。我正在操纵IPv6地址,并试图根据IPv6掩码确定给定的IPv6地址是否在子网内。

根据回复,我认为以下内容应该有效:

E.g。 是2001:db8:0:0:8:800:200c:417b在2001年:db8 :: / 64?

BigInteger n = new BigInteger(1, InetAddress.getByName("2001:db8::").getAddress());
BigInteger b = BigInteger.ONE.shiftLeft(64).subtract(BigInteger.ONE).shiftLeft(64);

// First Address in Subnet
BigInteger first = n.and(b);

// Last Address in Subnet (this is where I was having a problem as it was returning a negative number)
BigInteger MASK_128 = BigInteger.ONE.shiftLeft(128).subtract(BigInteger.ONE);
BigInteger last = first.add(b.xor(MASK_128));

// Convert our test IP into BigInteger
BigInteger ip = new BigInteger(1, InetAddress.getByName("2001:db8:0:0:8:800:200c:417b").getAddress());

// Check if IP is >= first and <= last
if ((first.compareTo(ip) <= 0) && (last.compareTo(ip) >= 0)) {
  // in subnet
}

4 个答案:

答案 0 :(得分:2)

正如其他人所指出的那样,它的标志位会给你一些你不想要的结果。

有两种方法可以获得反转位。对于它们两者,您将需要128位掩码值:

private static final BigInteger MASK_128 =
    BigInteger.ONE.shiftLeft(128).subtract(BigInteger.ONE);

然后你可以屏蔽符号位:

BigInteger b = BigInteger.valueOf(2).pow(64).subtract(BigInteger.ONE).shiftLeft(64);
System.out.println(MASK_128.andNot(b).toString(2));

或使用xor直接反转:

System.out.println(b.xor(MASK_128).toString(2));

我希望一旦你开始充实东西,掩码值在其他地方也会有用。

答案 1 :(得分:1)

有符号字节64 = 01000000

反转

我们得到签名字节-65 = 10111111

签署&#34;减去&#34;是&#34;不是&#34;运营商本身:

-1000000 = 0111111

键入此内容,您会看到绝对值

中的值相等(+1)
System.out.println(b.toString());
System.out.println(b.not().toString());

答案 2 :(得分:1)

你的回答是完全正确的,在java中,所有内容都是恭维:

将十进制转换为二的补码

将数字转换为二进制(暂时忽略该符号),例如5是0101,-5是0101

如果数字是正数,那么你就完成了。例如5是使用二进制补码表示法的二进制0101。

以下是您的解决方案。

If the number is negative then

3.1 find the complement (invert 0's and 1's) e.g. -5 is 0101 so finding the complement is 1010

3.2 Add 1 to the complement 1010 + 1 = 1011. Therefore, -5 in two's complement is 1011.

那么,如果你想在二进制文件中做2 +( - 3)怎么办? 2 +( - 3)为-1。如果您使用符号幅度来添加这些数字,您需要做什么? 0010 + 1101 =?

使用二进制补码考虑它是多么容易。

2 = 0010

-3 = 1101

+

-1 = 1111

将两个补码转换为十进制

将1111转换为十进制:

数字以1开头,所以它是负数,所以我们找到了1111的补码,即0000。

添加1到0000,我们获得0001。

将0001转换为十进制,即1。

应用sign = -1。

在你的情况下

当你b.not().toString(2)时,你会收到回复:

-11111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000001

最后一位 1

现在做两个人的恭维,你会得到正确的答案。

e.g;将所有 1 翻转为 0 ,反之亦然。在这之后添加一个解决方案,你将得到你正在寻求的解决方案。

最终解决方案

00000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111

答案 3 :(得分:0)

使用

VALUE = 0xFFFFFFFFFFFFFFFF0000000000000000 - 这是第1位... 10 ... 0

的模式

VALUE = 0x0000000000000000FFFFFFFFFFFFFFFF - 这是第0位... 01 ... 1

的模式

只需手动输入16 x“F”和“0”,并记住在每个模式之前添加“0x”。 将此值定义为最终值。

如果你想生成这样的值,你必须这样做 值+ = 0x1; 值&lt;&lt; 1; n次。在你的情况下,n是64。