只使用 += 和 -= 运算符,而不使用其他运算符或变量,是否可能交换两个变量的值?

14

我想要使用仅有+=-=运算符来交换两个变量的值,同时不使用临时变量。我知道标准的解决方案,例如:

a = a+b;
b = a-b;
a = a-b;

同时使用 xor

a ^= b;
b ^= a;
a ^= b;

但我不知道如何只使用+=-=实现它。这可能吗?


b -= 2 * b 怎么样? - Tom
3
谁将这个问题标记为“不具建设性”?这是一个非常精确的问题,它将有一个非常精确的答案(要么是几行代码,要么是“无法完成”)。它的实际用途可能会引起争议,但从编程/数学的角度来看,它是有效且有趣的。 - DevSolar
1
我不相信使用四个运算符a+=b,a-=b,b+=a,b-=a是可能的,但我无法证明。 - Tom
1
也许你是对的。而且你也可以使用 a+=aa-=a,第一个可能会有用。 - medvedNick
相反,如果这是一场综合数学/编程考试,那么“小林丸”(Kobayashi Maru)情况变得更加可能,因为我会期望数学学生能够正式证明这个任务的无用性。因此,我认为这就是它背后的想法。 - DevSolar
显示剩余17条评论
3个回答

10

我的同学们提供了一个很好的解决方案:答案是NO

我们把a表示为(1 0),把b表示为(0 1)

矩阵A

1 0
0 1

+=-=表示将行相加或相减。这意味着行列式要么不改变符号,要么等于0。最终矩阵为:

0 1
1 0

行列式等于-1,所以你无法得到它。

更新:你有以下操作:

  1. a-=a。一行变成0,因此det=0
  2. a+=a。那意味着将一行乘以2,因此det A'= 2*det A
  3. a+=b。这意味着进行初等变换,不改变det的值
  4. a-=b。与3.相同

然后对b-=bb+=bb+=ab-=a应用此证明。因此行列式没有改变其符号或者为0

更新2:正如@Tom在这里所说的:在C#中实现的示例:http://ideone.com/UzVLML。然而,在C语言中是不正确的:http://codepad.org/Rmhn9iqb。有人能澄清C和C#中b -= b += b的区别吗?


你能否指出一个证明,证明将行相加或相减不会改变行列式的符号? - MOHAMED
@medvedNick:你看,这就是我为什么是程序员而不是数学家的原因:我完全不知道你在说什么,但我会直接接受它。;-) - DevSolar
@MOHAMED 更新了回答并附上了证明,为什么行列式不会改变符号为-1。 - medvedNick
1
@melvedNick 在C语言中,b -= b += b是未定义行为,因为在同一表达式中有两个对b的赋值,且没有序列点介入。序列点是更新发生的标记,通常是;&&||bool ? true : false文章中的?、函数参数评估和从调用者到被调用者的控制传递之间的点、函数返回等等...只需搜索“序列点”与“未定义行为”,你就会明白。 - autistic

2
尽管 OP 已经证明这是不可能的,但我们在现代语言中可以作弊。
        a += b;
        b -= b += b; // Negates b in most languages, but not in C
        b += a;
        a -= b;

2
在 C 和 C++03 中,b -= b += b; 是未定义行为,因为在引用 b 的对象时存在两个写入操作而没有中间的序列点。在 C++11(其中没有序列点)中,我认为赋值表达式中的赋值被排序在赋值表达式的值计算之前,所以我认为它是有效的。 - CB Bailey
无论如何,b += b 不是 void 类型,它具有 b 的类型,并且计算结果为 b 的赋值后的值。 - CB Bailey
@CharlesBailey 感谢您的建议。是的,我意识到了并将其从帖子中删除了。 - Tom
1
@CharlesBailey:在C++11中,b -= b += b仍然是未定义的。 -=运算符左右两侧的求值相对于彼此是无序的,这意味着b的修改(在右侧)和b的值计算(在左侧)是无序的,从而导致未定义的行为。 - interjay
@interjay:哦,抱歉,我明白你的意思了。问题在于先前的值被“读取”,这与第一次写入的顺序不确定,这就是导致未定义行为的原因。是的,好观点。 - CB Bailey
显示剩余7条评论

0
    a +=b;
    b -=a;
    b =-b;
    a -=b;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接