该XOR值交换算法是否仍在使用或有用


25

当我刚开始工作时,大型机组装程序程序员向我展示了如何在不使用传统算法的情况下将它们交换为值:

a = 0xBABE
b = 0xFADE

temp = a
a = b
b = temp

他们用来交换两个值(从一点到一个大的缓冲区)的是:

a = 0xBABE
b = 0xFADE

a = a XOR b
b = b XOR a
a = a XOR b

现在

b == 0xBABE
a == 0xFADE

它交换了2个对象的内容,而无需第三个临时存储空间。

我的问题是:这个XOR交换算法是否仍在使用,它仍然在哪里适用。


50
它仍然被广泛用于炫耀和不好的面试问题。就是这样。
Michael Borgwardt 2013年

4
这是否像把戏一样:a = a + b,b = ab,a = ab?
Pieter B

4
@PieterB是的,他们是这两种情况stackoverflow.com/questions/1826159/...
JK。

因此,您保存了注册表,但还需要支付3条指示。我认为临时版本无论如何都会更快。
Billy ONeal

1
由于xchg指令,@ MSalters值交换从一开始就不在x86中成为问题。OTOH交换2个内存位置需要3个xchg :)
Netch

Answers:


41

使用时,xorswap存在将两个变量都提供给该函数的变量的危险,该函数会将所述变量归零,这是因为将其xor与自身变量一起将所有位都置零。当然,无论使用哪种算法,它本身都会导致不良行为,但是这种行为可能令人惊讶,乍一看并不明显。

传统上,xorswap它已用于在寄存器之间交换数据的低级实现。实际上,在寄存器中交换变量有更好的选择。例如,英特尔的x86具有一条XCHG指令,该指令交换两个寄存器的内容。很多时候,编译器会弄清楚此类函数的语义(它会交换传递给它的值的内容),并在需要时可以进行自己的优化,因此,尝试像交换函数一样琐碎的优化并不能真正为您带来任何好处在实践中。最好使用显而易见的方法,除非有充分的理由说明在问题域内说xorswap不如说有道理。


18
如果两个值相同,那么您仍然可以得到正确的结果。 a: 0101 ^ 0101 = 0000; b: 0101 ^ 0000 = 0101; a: 0101 ^ 0000 = 0101;
BOBSON

1
@ GlenH7说了什么。 -1-> +1
Bobson

1
您似乎仍然有这样的说法:“使用xorswap时,有可能为函数的两个参数提供相同的变量,该变量会将所述变量与自己进行异或运算,从而将所有位都变为零,从而将所述变量清零。”。 ..那不是要删除吗?
克里斯(Chris

9
@Chris不,起初我曾写过,如果值与if相同a=10, b=10,并且如果您这样做xorswap(a,b),则可以,并且不会将错误的变量清零,现在将其删除。但是,如果您这样做了,xorswap(a, a)a我本来是指愚蠢的,便会归零。:)
zxcdw

3
在某些语言中这是非常相关的-这样的小小的危险使得将来在处理两个指针时都很难找到bug,而这两个指针被设置为指向同一地址,并且指向100多个您看不到的行。
德雷克·克拉里斯2013年

14

答案的关键是在编译器问世之前的问题-“工作大型机汇编程序”。当人们急于准备组装指令并为特定的硬件手工制作精确的解决方案(可能在同一台计算机的另一种型号上工作或可能不工作)时,诸如硬盘驱动器和感光鼓内存的时间等问题都会影响代码的编写方式。书面- 如果需要怀旧,请阅读《梅尔的故事》

在过去的日子里,寄存器和内存都很稀缺,不必花任何时间从主架构师那里请求另一个字节或内存字的技巧就节省了时间-既节省了代码编写时间,又节省了执行时间。

那些日子已经一去不复返了。不使用第三项就交换两件事的技巧是一个技巧。内存和寄存器在现代计算中都非常丰富,人们不再编写汇编程序。我们已经向编译器教授了所有技巧,并且它们比我们做得更好。编译器可能比我们所做的还要好。在大多数情况下,有时出于某种原因,我们需要在紧密循环的某些内部编写汇编程序……但这并不是要保存寄存器或内存字。

如果在特别有限的微控制器中工作,这可能再次有用,但是优化交换不太可能成为问题的根源-试图变得太聪明可能是一个问题。


2
在许多情况下,寄存器实际上并不是那么丰富。即使处理器有足够的寄存器供应,ISR中使用的每个寄存器都是必须事先保存然后再恢复的寄存器。如果ISR需要二十个周期,并且假定每40个周期运行一次,那么添加到ISR的每个额外周期将使系统性能降低5个百分点。
2015年

8

能行吗 是。

你应该使用它吗?没有。

在以下情况下,这种微观优化是有意义的:

  • 您已经查看了编译器为执行此操作的直接方式(赋值和临时操作)而生成的代码,并决定了XOR方法生成更快的代码

  • 您已经对应用程序进行了概要分析,发现直接方法的成本超过了代码的清晰度(从而节省了可维护性)

首先,除非进行了此度量,否则您应该信任编译器。当您要执行的操作的语义很明确时,编译器可以做很多技巧,包括重新排列变量访问以使根本不需要交换,或者内联任何提供最快速度的机器级指令交换给定的数据类型。诸如XOR交换之类的“技巧”使编译器更难查看您要执行的操作,因此使其无法应用此类优化。

第二点,您从增加的复杂性中获得了什么?即使您已经更快地测量并发现了XOR方法,这是否足以证明一个不太清晰的方法?你怎么知道的?

最后,您应该研究平台/语言是否具有标准交换功能-例如,C ++ STL提供了模板交换功能,该模板交换功能将针对您的编译器/平台进行高度优化。


2

我的同事报告说,这是他在大学教给自动化系统程序员学习的基本技巧。许多这样的系统是嵌入式系统,资源有限,它们可能缺少免费注册来保持临时价值。在这种情况下,这种棘手的交换(或其加减法模拟)变得至关重要,因此仍在使用。

但是请注意,这两个位置不能相同,因为在后一种情况下,这两个位置实际上将为零。因此通常它仅限于显而易见的情况,例如交换寄存器和存储位置。

对于x86,xchg和cmpxchg指令在大多数情况下可以满足需要,但是RISC通常不包含在其中(Sparc除外)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.