过多讨论异或交换技巧。
Too much discussion of the XOR swap trick

原始链接: https://heather.cafe/posts/too_much_xor_swap_trick/

## XOR 交换技巧:深入剖析 本文探讨了 XOR 交换技巧——一种无需使用临时变量来交换两个变量的方法——并最终质疑其实用性。该技巧利用了 XOR(异或)运算的特性:自反性(a ^ a = 0)和恒等性(a ^ 0 = a)。 虽然看似巧妙,但编译器很容易优化掉本地变量的 XOR 交换,生成与传统交换或直接操作相同的代码。即使应用于指针交换,XOR 方法始终会产生比简单临时变量交换更慢、更复杂的汇编代码。一个关键缺点是,XOR 交换指向*相同*内存位置的两个指针会导致数据丢失,而临时变量交换则不会。 XOR 交换的特定用例出现在低级汇编编程中,在寄存器限制非常严格的情况下。然而,即使在那种情况下,也通常存在专门的交换指令(例如 x86 的 XCHG),使得 XOR 变得不必要。尽管 XOR 的实际价值有限,但它具有合法的应用,例如有效地找到列表中唯一元素,而所有其他元素出现两次。最终,XOR 交换技巧更像是一种编程好奇心和面试问题,而不是现代编程中真正有用的技术。

``` Hacker News新帖 | 历史 | 评论 | 提问 | 展示 | 招聘 | 提交登录 太多关于异或交换技巧的讨论 (heather.cafe) 5 分,CJefferson 发表于 2 小时前 | 隐藏 | 历史 | 收藏 | 讨论 帮助 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索: ```
相关文章

原文

The following post involves far too much discussion of the XOR swap trick. I suspect many readers already know some of this, so feel free to skip over some early sections if you like! If you already know what the XOR swap trick is, you can skip straight to the part where we see if it’s useful.

XOR is short for Exclusive OR (we use the X, instead of EOR, because X is cooler). XOR has a lesser known, less cool friend, Inclusive Or (IOR).

These two names comes from an issue in English (and many other languages), where we use ‘or’ for two different purposes. The difference between these two is when someone talks about “A or B”, are you allowed both A and B, or just one or the other? In maths and computing, where we need to be more exact, we separate these two cases into XOR (you cannot have both) and IOR (you can have both).

To hopefully make this clearer, let’s consider a couple of real world examples. I decided to pick a couple of examples from the Disney World website. Let’s begin by picking one of the rules of Disney World, you cannot “harass or harm wildlife” – reasonable sounding rule! If you started kicking a duck while also insulting it, you would be both harassing and harming wildlife. This is clearly an ‘inclusive’ or, if you tried to claim you were not “harassing or harming wildlife, I’m doing both!”, you would still get kicked out of the park.

On the other hand, over in the Refreshment Corner, the “All-Beef Hot Dog Basket” comes with a “Mandarin Orange or a Small Bag of Chips”. Here, the ‘or’ is exclusive, you can have an orange, you can have chips, but you cannot have an orange and chips! No matter how much you pointed at the person being dragged out of the park for duck harassment and harming, Disney are not going to agree their rules are inconsistent.

How do we know if an ‘or’ is inclusive or exclusive? There are some general rules, but often you just have to know by context. However, because we want to be clear when using computers, we are going to use ‘XOR’ when we mean “A, or B, but not both”.

A logical XOR takes two true/false values and returns true when exactly one of the two is true. We can write this out as a table:

false false false
false true true
true false true
true true false

One useful way to think about XOR: A XOR B is the same as asking “are A and B different?” If they are different, the result is true. If they are the same, the result is false. This will become important later.

In most programming languages, the ^ operator performs a bitwise XOR. This means it takes two integers, lines up their binary representations, and applies logical XOR to each pair of bits independently.

For example, let’s XOR the numbers 12 and 10:

  12 = 1100
  10 = 1010
  ----------
  ^  = 0110 = 6

Each column is just a logical XOR: 1 XOR 1 = 0, 1 XOR 0 = 1, 0 XOR 1 = 1, 0 XOR 0 = 0.

Bitwise XOR has two properties that matter for the swap trick:

  1. Self-inverse: a ^ a == 0 for any value a. Every bit cancels with itself.
  2. Identity: a ^ 0 == a. XOR with zero changes nothing.

Combining these: if we compute a ^ b ^ b, the two bs cancel and we get back a. This works the other way too: a ^ b ^ a gives us b. Hold that thought.

The XOR swap trick uses those properties to swap two variables without a temporary variable. Here it is in C:

Let’s trace through this with a = 5 and b = 3:

Start 5 3
Line 1 a ^= b 5 ^ 3 = 6 3
Line 2 b ^= a 6 3 ^ 6 = 5
Line 3 a ^= b 6 ^ 5 = 3 5

After line 1, a holds a ^ b. After line 2, b holds b ^ (a ^ b) which simplifies to a (the bs cancel). After line 3, a holds (a ^ b) ^ a which simplifies to b (the as cancel). The values have been swapped, and we never needed a temporary variable.

This is a clever bit of programming, and you can find it discussed in many places online. The question is: is it actually useful? Let’s find out.

The most common place you might want to swap two variables is right there in a function, with local variables. So let’s write three functions and see what the compiler makes of them. First, a baseline – just return a / b: