【发布时间】:2017-08-27 20:51:38
【问题描述】:
我试图在 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 输出,结果如下:
111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000
我正在尝试使用按位不翻转/反转所有位。
System.out.println(b.not().toString(2));
从我的理解来看,我希望所有的 1 都变成 0,所有的 0 都变成 1,但我得到了以下结果:
-111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000
这似乎也符合not()函数的文档:
此方法返回负值当且仅当此 BigInteger 为非负数时
是不是循环遍历所有 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
}
【问题讨论】:
-
我的猜测是符号位发生了什么事。
-
Java 是二进制补码。你确实得到了翻转的位,然后它打印出一个有符号的二进制数。
-
是否可以将其视为无符号数?
-
@chrixm 无关,但为什么是
BigInteger而不是BitSet? -
请注意,对于所有值,
x.not()等于x.negate().subtract(BigInteger.ONE)(试试看)。我想这解释了你得到的结果。
标签: java math bit-manipulation biginteger