이 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

4
이것은 트릭과 같은 것입니까? a = a + b, b = ab, a = ab?
피터 B

4
@PieterB 예,이 두 가지 경우입니다
.

그래서 ... 등록을 저장하지만 3 가지 추가 지침으로 지불하십시오. 어쨌든 임시 버전이 더 빠를 것이라고 생각합니다.
Billy ONeal

1
@MSalters 값 스왑은 xchg 명령으로 인해 처음부터 x86에서 문제가되지 않았습니다. 2 개의 메모리 위치를 교환하는 OTOH는 3 xchgs를 필요로합니다 :)
Netch

답변:


41

사용할 때 모든 비트를 0으로 바꾸는 자체 xorswap변수로 인해 변수를 제로화하는 함수에 두 인수와 동일한 변수를 제공 할 위험이 xor있습니다. 물론 이것은 자체적으로 사용 된 알고리즘에 관계없이 원치 않는 동작을 야기 할 수 있지만, 그 동작은 놀랍고 언뜻보기에는 분명하지 않을 수 있습니다.

전통적 xorswap으로 레지스터 간 데이터 교환을위한 저수준 구현에 사용되었습니다. 실제로 레지스터에서 변수를 교체하는 더 나은 대안이 있습니다. 예를 들어 인텔의 x86에는 XCHG두 레지스터의 내용을 바꾸는 명령이 있습니다. 종종 컴파일러는 그러한 함수의 의미를 파악하고 (필요한 값의 내용을 교환) 필요한 경우 자체 최적화를 수행 할 수 있으므로 스왑 함수처럼 사소한 것을 최적화하려고 시도해도 실제로 아무것도 사지 않습니다. 실제로. 문제 영역 내에서 xorswap을 말하는 것이 열등한 이유가없는 한 명백한 방법을 사용하는 것이 가장 좋습니다.


18
두 값이 모두 같은 경우에도 올바른 결과가 나타납니다. a: 0101 ^ 0101 = 0000; b: 0101 ^ 0000 = 0101; a: 0101 ^ 0000 = 0101;
Bobson

1
@ GlenH7이 말한 것. -1-> +1.
밥슨

1
"xorswap을 사용할 때 모든 변수를 0으로 바꾸는 xor'd로 인해 변수를 0으로 만드는 함수에 두 인수와 동일한 변수를 제공 할 위험이 있습니다." .. 제거되지 않았습니까?
Chris

9
@Chris No, 처음에는 값이 if a=10, b=10와 같으면 xorswap(a,b)작동하고 작동하면 거짓이고 이제 제거 된 변수를 제로화하지 않을 것이라고 썼습니다 . 그러나 당신이 xorswap(a, a)그때 a내가 원래 의미했지만 어리석은 제로를 얻을 것입니다. :)
zxcdw

3
특정 언어에서는 매우 관련이 있습니다. 작은 작은 위험은 보이지 않는 동일한 주소 100 개를 가리 키도록 설정된 두 개의 포인터를 처리 할 때 장래에 버그를 찾기가 어려워집니다.
Drake Clarris

14

대답의 핵심은 컴파일러 전날 "메인 프레임 어셈블러 프로그래머 작업"이라는 질문에 있습니다. 인간이 특정 하드웨어에 대한 조립 지침과 수작업으로 정확한 하드웨어를 만들었을 때 (동일한 컴퓨터의 다른 모델에서는 작동하거나 작동하지 않을 수 있음) 하드 드라이브 및 드럼 메모리의 타이밍과 같은 문제는 코드의 작동 방식에 영향을 미쳤습니다 서면- 향수를 불러 일으킬 필요가 있다고 생각되면 Mel의 이야기를 읽으십시오 ).

과거에는 레지스터와 메모리가 거의 없었으며 코드를 작성하고 실행하는 시간에서 리드 아키텍트의 다른 바이트 나 메모리를 구걸하지 않아도되는 시간이 절약되었습니다.

그 시절은 지났습니다. 세 번째를 사용하지 않고 두 가지를 바꾸는 트릭은 속임수입니다. 메모리와 레지스터는 현대 컴퓨팅에서 풍부하며 인간은 더 이상 어셈블리를 쓰지 않습니다. 우리는 모든 트릭을 컴파일러에 가르쳤으며 우리보다 더 나은 작업을 수행합니다. 컴파일러가 우리가 한 것보다 더 나은 일을했을 가능성이 있습니다. 대부분의 경우 때때로 어떤 이유로 타이트한 루프의 내부 비트에 어셈블리를 작성해야하지만 레지스터 나 메모리를 저장하지는 않습니다.

특히 제한된 마이크로 컨트롤러에서 작업하는 경우 다시 유용하지만 스왑 최적화는 문제의 원인이 아닐 수 있습니다. 너무 영리한 시도는 문제 일 가능성이 큽니다.


2
레지스터는 많은 맥락에서 실제로 그렇게 많지 않습니다. 프로세서에 충분한 레지스터 공급 장치가 있더라도 ISR에 사용되는 모든 레지스터는 미리 저장 한 후 나중에 복원해야하는 레지스터입니다. ISR이 20주기를 수행하고 40주기마다 실행되어야하는 경우 ISR에 추가되는 각 추가주기는 시스템 성능을 5 % 포인트 떨어 뜨립니다.
supercat

8

작동합니까? 예.

사용해야합니까? 아니.

다음과 같은 경우 이러한 종류의 미세 최적화 가 의미가 있습니다.

  • 컴파일러 가이 작업을 수행하는 간단한 방법 (할당 및 임시)을 위해 생성하는 코드를 살펴보고 XOR 접근 방식이 더 빠른 코드를 생성하기로 결정했습니다.

  • 앱을 프로파일 링했으며 간단한 접근 방식의 비용이 코드의 선명도를 능가한다는 사실을 발견했습니다 (결과적으로 유지 관리 비용 절감)

먼저,이 측정을 수행하지 않으면 컴파일러를 신뢰해야합니다. 당신이하려는 일의 의미가 분명 할 때, 스왑이 전혀 필요하지 않도록 변수 액세스를 재 배열하거나 머신 레벨 명령이 가장 빠른 것을 인라인으로 지정하는 것을 포함하여 컴파일러가 할 수있는 많은 트릭이 있습니다. 주어진 데이터 유형으로 교체하십시오. XOR 스왑과 같은 "트릭"을 사용하면 컴파일러가 수행하려는 작업을 확인하기가 어려워서 이러한 최적화를 적용 할 수 없게됩니다.

두 번째로, 추가 된 복잡성을 위해 무엇을 얻고 있습니까? XOR 접근 방식을 더 빨리 측정하고 찾았더라도 덜 명확한 접근 방식을 정당화하기에 충분한 영향을 미칩니 까? 당신은 어떻게 알 수 있습니까?

마지막으로, 플랫폼 / 언어에 대한 표준 스왑 기능이 있는지 확인해야합니다. 예를 들어 C ++ STL은 컴파일러 / 플랫폼에 최적화 된 템플릿 스왑 기능을 제공합니다.


2

저의 동료는 이것이 자동화 시스템 프로그래머를 위해 공부하는 대학에서 가르친 기본 기술이라고보고했습니다. 이러한 많은 시스템에는 제한된 리소스를 가진 시스템이 내장되어 있으며 임시 값을 유지할 수있는 무료 레지스터가 부족할 수 있습니다. 이 경우, 그러한 까다로운 교환 (또는 더하기와 빼기가있는 아날로그)은 여전히 ​​중요하므로 여전히 사용되고 있습니다.

그러나 후자의 경우 두 값이 모두 0이기 때문에 두 위치가 동일 할 수 없다는 점을 염두에 두어야합니다. 따라서 일반적으로 레지스터 및 메모리 위치 교환과 같은 명백한 경우로 제한됩니다.

x86을 사용하면 xchg 및 cmpxchg 명령어는 대부분의 경우 필요를 충족하지만 RISC는 일반적으로 해당 명령어로 다루지 않습니다 (Sparc 제외).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.