Java BigInteger 的按位非是负数
Bitwise NOT of Java BigInteger is Negative
我正在尝试对 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));
如果我使用基数 2 输出结果如下:
111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000=00600
我正在尝试 flip/reverse 所有位使用按位非。
System.out.println(b.not().toString(2));
根据我对按位非的理解,我希望所有的 1 都变成 0,所有的 0 都变成 1,但我得到的却是:
- 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111起至高20000000000000000000000000000000000000000000000000000000000000000000000 [= 16 = 16 =]
这似乎也符合 not()
函数的文档:
This method returns a negative value if and only if this BigInteger is non-negative
是否循环遍历所有 128 位,而不是对每个单独的位执行按位运算?
更新
如果我尝试解释我试图实现的目标以提供一些背景信息,这可能会有所帮助。我正在操作 IPv6 地址,并试图根据 IPv6 掩码确定给定的 IPv6 地址是否在子网内。
根据回复,我认为以下应该可行:
例如
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
}
有符号字节 64 = 01000000
反转它
我们得到有符号字节 -65 = 10111111
符号"minus"是"not"运算符本身:
-1000000 = 0111111
键入此内容,您会看到绝对值等于 (+1)
System.out.println(b.toString());
System.out.println(b.not().toString());
你的回答是完全正确的,在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
0000加1,得到0001。
将 0001 转换为十进制,即 1。
应用符号 = -1。
你的情况
当您执行 b.not().toString(2)
时,您将得到响应:
-11111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000001
在最后一位 1。
现在做两人的赞美,你会得到正确的答案。
例如;将所有 1 的 翻转 0 的 ,反之亦然。这样做之后,将一个添加到解决方案中,您将得到您正在寻找的解决方案。
最终解
00000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111
正如其他人所指出的,是符号位给了您不想要的结果。
有几种方法可以获得反转位。对于它们两者,您都需要一个 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));
或者直接用异或取反:
System.out.println(b.xor(MASK_128).toString(2));
我希望掩码值在您开始充实内容后在其他地方也会有用。
使用
VALUE = 0xFFFFFFFFFFFFFFFF0000000000000000 - 这是位 1...10...0
的模式
VALUE = 0x0000000000000000FFFFFFFFFFFFFFFF - 这是位 0...01...1
的模式
只需手动输入 16 x "F" 和“0”,并记得在每个模式前添加“0x”。
将此值定义为最终值。
如果你想生成这样的值你必须做
值 += 0x1;
值 << 1;
对于 n 次。在你的例子中 n 是 64.
我正在尝试对 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));
如果我使用基数 2 输出结果如下:
111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000=00600
我正在尝试 flip/reverse 所有位使用按位非。
System.out.println(b.not().toString(2));
根据我对按位非的理解,我希望所有的 1 都变成 0,所有的 0 都变成 1,但我得到的却是:
- 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111起至高20000000000000000000000000000000000000000000000000000000000000000000000 [= 16 = 16 =]
这似乎也符合 not()
函数的文档:
This method returns a negative value if and only if this BigInteger is non-negative
是否循环遍历所有 128 位,而不是对每个单独的位执行按位运算?
更新 如果我尝试解释我试图实现的目标以提供一些背景信息,这可能会有所帮助。我正在操作 IPv6 地址,并试图根据 IPv6 掩码确定给定的 IPv6 地址是否在子网内。
根据回复,我认为以下应该可行:
例如 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
}
有符号字节 64 = 01000000
反转它
我们得到有符号字节 -65 = 10111111
符号"minus"是"not"运算符本身:
-1000000 = 0111111
键入此内容,您会看到绝对值等于 (+1)
System.out.println(b.toString());
System.out.println(b.not().toString());
你的回答是完全正确的,在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
0000加1,得到0001。
将 0001 转换为十进制,即 1。
应用符号 = -1。
你的情况
当您执行 b.not().toString(2)
时,您将得到响应:
-11111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000001
在最后一位 1。
现在做两人的赞美,你会得到正确的答案。
例如;将所有 1 的 翻转 0 的 ,反之亦然。这样做之后,将一个添加到解决方案中,您将得到您正在寻找的解决方案。
最终解
00000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111
正如其他人所指出的,是符号位给了您不想要的结果。
有几种方法可以获得反转位。对于它们两者,您都需要一个 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));
或者直接用异或取反:
System.out.println(b.xor(MASK_128).toString(2));
我希望掩码值在您开始充实内容后在其他地方也会有用。
使用
VALUE = 0xFFFFFFFFFFFFFFFF0000000000000000 - 这是位 1...10...0
的模式VALUE = 0x0000000000000000FFFFFFFFFFFFFFFF - 这是位 0...01...1
的模式只需手动输入 16 x "F" 和“0”,并记得在每个模式前添加“0x”。 将此值定义为最终值。
如果你想生成这样的值你必须做 值 += 0x1; 值 << 1; 对于 n 次。在你的例子中 n 是 64.