给定两个数字的 XOR & SUM。如何找到数字?例如,x = a+b,y = a^b;如果给定 x,y,如何得到 a,b?如果不能,请给出原因。
4 回答
这不能可靠地完成。一个反例足以摧毁任何理论,在你的情况下,这个例子是0, 100
and 4, 96
。这两个总和100
和异100
或也是:
0 = 0000 0000 4 = 0000 0100
100 = 0110 0100 96 = 0110 0000
---- ---- ---- ----
xor 0110 0100 = 100 xor 0110 0100 = 100
因此,给定 的总和100
和 的异或100
,您无法知道哪种可能性产生了这种情况。
对于它的价值,这个程序只用数字检查可能性0..255
:
#include <stdio.h>
static void output (unsigned int a, unsigned int b) {
printf ("%u:%u = %u %u\n", a+b, a^b, a, b);
}
int main (void) {
unsigned int limit = 256;
unsigned int a, b;
output (0, 0);
for (b = 1; b != limit; b++)
output (0, b);
for (a = 1; a != limit; a++)
for (b = 1; b != limit; b++)
output (a, b);
return 0;
}
然后,您可以获取该输出并对其进行按摩,以提供所有重复的可能性:
testprog | sed 's/ =.*$//' | sort | uniq -c | grep -v ' 1 ' | sort -k1 -n -r
这使:
255 255:255
128 383:127
128 319:191
128 287:223
128 271:239
128 263:247
:
and so on.
即使在那个简化的集合中,也有相当多的组合会产生相同的和和异或,最糟糕的是产生 的和/异或的大量可能性255/255
,它们是:
255:255 = 0 255
255:255 = 1 254
255:255 = 2 253
255:255 = <n> <255-n>, for n = 3 thru 255 inclusive
已经表明它无法完成,但这里有两个进一步的原因。
对于 a's 和 b's 的(相当大的)子集(a & b) == 0
,你有a + b == (a ^ b)
(因为不能有进位)(相反的含义不成立)。在这种情况下,对于总和中为 1 的每个位,您可以选择哪个位a
或b
贡献该位。显然这个子集并没有覆盖整个输入,但至少证明了一般情况下是做不到的。
此外,存在许多对,(x, y)
因此没有解决方案a + b == x && (a ^ b) == y
,例如(不止这些)所有对((x, y)
即((x ^ y) & 1) == 1
一个是奇数,另一个是偶数),因为 xor 的最低位和总和相等(最低位没有进位)。通过一个简单的计数论证,这必须意味着至少一些对(x, y)
必须有多个解决方案:显然所有对(a, b)
都有一些(x, y)
与它们相关联的对,所以如果不是所有对(x, y)
都可以使用,那么(x, y)
必须共享一些其他对。
这是获得所有此类对的解决方案
逻辑:让数字是a和b,我们知道
s = a + b
x = a ^ b
所以
x = (s-b) ^ b
因为我们知道 x 并且我们知道 s,所以对于从 0 到 s 的所有整数 - 只需检查最后一个方程是否满足
这是这个的代码
public List<Pair<Integer>> pairs(int s, int x) {
List<Pair<Integer>> pairs = new ArrayList<Pair<Integer>>();
for (int i = 0; i <= s; i++) {
int calc = (s - i) ^ i;
if (calc == x) {
pairs.add(new Pair<Integer>(i, s - i));
}
}
return pairs;
}
类对定义为
class Pair<T> {
T a;
T b;
public String toString() {
return a.toString() + "," + b.toString();
}
public Pair(T a, T b) {
this.a = a;
this.b = b;
}
}
测试这个的代码:
public static void main(String[] args) {
List<Pair<Integer>> pairs = new Test().pairs(100,100);
for (Pair<Integer> p : pairs) {
System.out.println(p);
}
}
输出:
0,100
4,96
32,68
36,64
64,36
68,32
96,4
100,0
如果你有 a , b 总和 = a+b = (a^b) + (a&b)*2 这个等式可能对你有用