このXOR値スワップアルゴリズムはまだ使用中または有用ですか


25

私が最初に働き始めたとき、メインフレームのアセンブラープログラマーは、以下の従来のアルゴリズムを使用せずに値にスワップする方法を示しました。

a = 0xBABE
b = 0xFADE

temp = a
a = b
b = temp

彼らが2つの値を交換するのに使用したもの-ビットから大きなバッファまで-は:

a = 0xBABE
b = 0xFADE

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

b == 0xBABE
a == 0xFADE

3番目の一時保持スペースを必要とせずに2つのオブジェクトの内容を交換しました。

私の質問は次のとおりです。このXORスワップアルゴリズムはまだ使用されており、どこに適用できるのでしょうか。


50
面接や悪いインタビューの質問を自慢するためにまだ広く使われています。それはそれについてです。
マイケルボルグワード

4
これはトリックのようなものですか:a = a + b、b = ab、a = ab?
ピーターB

4
@PieterBはい、彼らは、この両方のケースであるstackoverflow.com/questions/1826159/...
JK。

だから...あなたはレジスタを保存しますが、さらに3つの指示で支払います。とにかく一時バージョンの方が速いと思います。
ビリーONeal

1
xMSでは、xchg命令により、@ MSalters値のスワップは最初からx86の問題ではありませんでした。2つのメモリ位置を交換するOTOHは3 xchgsを必要とします:)
Netch

回答:


41

使用する場合xorswapxorすべてのビットをゼロに変更するために変数をゼロにする関数の両方の引数として同じ変数を提供する危険があります。もちろん、これ自体は、使用されるアルゴリズムに関係なく、望ましくない動作をもたらしますが、動作は驚くべきものであり、一見すると明らかではありません。

従来xorswap、レジスタ間でデータを交換するための低レベルの実装に使用されてきました。実際には、レジスタ内の変数を交換するためのより良い代替手段があります。たとえば、Intelのx86には、XCHG2つのレジスタの内容を交換する命令があります。多くの場合、コンパイラはそのような関数のセマンティクスを把握し(渡された値の内容をスワップします)、必要に応じて独自の最適化を行うことができるため、スワップ関数ほど些細なものを最適化しようとしても何も買わない実際には。問題領域内でxorswapと言うのが劣るという証明された理由がない限り、明白な方法を使用するのが最善です。


18
両方の値が同じ場合でも、正しい結果が得られます。 a: 0101 ^ 0101 = 0000; b: 0101 ^ 0000 = 0101; a: 0101 ^ 0000 = 0101;
ボブソン

1
@ GlenH7が言ったこと。 -1-> +1
ボブソン

1
「xorswapを使用する場合、すべてのビットをゼロにするxor'dによってxor'dされているため、変数をゼロにする関数の両方の引数と同じ変数を提供する危険がある」という行があるようです。 ..削除されたわけではありませんか?
クリス

9
@Chrisいいえ、最初は、値がifのようa=10, b=10に同一であれば、もしxorswap(a,b)それを行うと、falseで現在削除されている変数をゼロにせずに機能することを書きました。あなたがなかった場合でも、xorswap(a, a)その後、aこれをゼロになるだろう、私はもともと意図していたが、愚かされていました。:)
zxcdw

3
特定の言語ではかなり関連性があります-そのような小さな小さな危険は、どういうわけかあなたが見ない100+行の同じアドレスを指すように設定された2つのポインタを扱うときに将来バグを見つけるのを難しくします。
ドレイククラリス

14

答えの鍵は、「メインフレームアセンブラープログラマーを動かす」という質問にあります。これは、コンパイラーの数日前のことです。人間が特定のハードウェアに合わせてアセンブリ命令と手作りの正確なソリューションを探し求めたとき(同じコンピューターの別のモデルで動作する場合と動作しない場合があります-ハードドライブやドラムメモリのタイミングなどの問題は、コードの方法に影響を与えました書かれた- ノスタルジックである必要性を感じたら、The Story of Melを読んでください)。

過去に遡ると、レジスタとメモリの両方が不足しており、コードと実行時間の両方を書くことで、リードアーキテクトから別のバイトまたはメモリのワードを要求する必要のないトリックが節約されました。

当時は過ぎ去りました。3つを使用せずに2つのものを交換するトリックはトリックです。メモリとレジスタはどちらも現代のコンピューティングに豊富にあり、人間はもはやアセンブリを記述しません。私たちはコンパイラーにすべてのトリックを教えてきましたが、彼らは私たちよりも良い仕事をしています。コンパイラは、私たちがしたことよりもさらに良いことをした可能性があります。ほとんどの場合、何らかの理由でタイトループの内部ビットでアセンブリを記述する必要がある場合がありますが、レジスタまたはメモリのワードを保存することではありません。

特に限られたマイクロコントローラーで作業している場合は再び役立つかもしれませんが、スワップを最適化することは問題の原因ではない可能性があります-賢すぎることを試みることは問題である可能性が高くなります。


2
レジスターは、多くのコンテキストでそれほど豊富ではありません。プロセッサに十分な数のレジスタがある場合でも、ISRで使用されるすべてのレジスタは、事前に保存して後で復元する必要があるレジスタです。ISRが20サイクルかかり、40サイクルごとに実行することになっている場合、ISRに追加される各サイクルは、システムパフォーマンスを5パーセントポイント低下させます。
supercat

8

機能しますか?はい。

あなたはそれを使うべきですか?いや

この種のマイクロ最適化は、次の場合に意味があります。

  • これを行う簡単な方法(割り当てと一時的)のためにコンパイラが生成するコードを見て、XORアプローチがより高速なコードを生成することを決定しました。

  • アプリのプロファイルを作成し、簡単なアプローチのコストがコードの明快さよりも重要であることがわかりました(そして結果として保守性が節約されます)。

最初に、この測定を行っていない限り、コンパイラを信頼する必要があります。実行しようとしていることのセマンティクスが明確な場合、スワップをまったく必要としないように変数アクセスを再配置したり、最速のマシンレベルの命令をインライン化するなど、コンパイラーが実行できる多くのトリックがあります指定されたデータ型のスワップ。XORスワップなどの「トリック」は、コンパイラーが何をしようとしているかを確認するのを難しくし、そのような最適化を適用できなくなります。

2番目のポイントまで、追加された複雑さのために何を得ていますか?XORアプローチをより速く測定して見つけたとしても、これはあまり明確でないアプローチを正当化するのに十分な影響を与えていますか?どうして知っていますか?

最後に、プラットフォーム/言語用の標準スワップ関数があるかどうかを調べる必要があります。たとえば、C ++ STLは、コンパイラ/プラットフォーム用に高度に最適化される傾向があるテンプレートスワップ関数を提供します。


2

私の同僚は、これは大学で自動化システムのプログラマーのために勉強した基本的なトリックだと報告しました。そのようなシステムの多くは、リソースが限られている組み込みシステムであり、一時的な値を保持するための無料のレジスタが不足している可能性があります。その場合、そのようなトリッキーな交換(または加算と減算を伴うそのアナログ)は非常に重要になっているため、まだ使用されています。

しかし、後者の場合は両方の値が事実上ゼロになるため、これらの2つの場所は同一にできないことに注意してください。そのため、通常は、レジスタやメモリの場所を交換するなどの明らかなケースに限定されています。

x86では、xchg命令とcmpxchg命令はほとんどの場合に必要を満たしますが、RISCは通常それらでカバーされません(Sparcを除く)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.