อัลกอริทึมการแลกเปลี่ยนค่า 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?
Pieter B

4
@PieterB ใช่ทั้งสองกรณีของstackoverflow.com/questions/1826159/
jk

ดังนั้น ... คุณบันทึกการลงทะเบียน แต่จ่ายด้วย 3 คำแนะนำเพิ่มเติม ฉันคิดว่าเวอร์ชันชั่วคราวจะเร็วกว่าอยู่ดี
Billy ONeal

1
การแลกเปลี่ยนค่า @MSalters ไม่ได้มีปัญหาใน x86 ตั้งแต่เริ่มต้นเนื่องจากคำสั่ง xchg OTOH การสลับตำแหน่งหน่วยความจำ 2 ตำแหน่งต้องการ 3 xchgs :)
Netch

คำตอบ:


41

เมื่อใช้งานจะxorswapมีอันตรายจากการให้ตัวแปรเดียวกันกับทั้งสองอาร์กิวเมนต์ของฟังก์ชันที่เลขศูนย์ตัวแปรดังกล่าวเนื่องจากมันเป็นxor'd กับตัวเองซึ่งจะเปลี่ยนบิตทั้งหมดให้เป็นศูนย์ แน่นอนว่าสิ่งนี้เองจะส่งผลให้เกิดพฤติกรรมที่ไม่ต้องการโดยไม่คำนึงถึงอัลกอริธึมที่ใช้ แต่พฤติกรรมนั้นอาจจะน่าประหลาดใจและไม่ชัดเจนในตอนแรก

ตามเนื้อผ้าxorswapถูกนำมาใช้สำหรับการใช้งานในระดับต่ำสำหรับการแลกเปลี่ยนข้อมูลระหว่างการลงทะเบียน ในทางปฏิบัติมีทางเลือกที่ดีกว่าสำหรับการแลกเปลี่ยนตัวแปรในการลงทะเบียน ตัวอย่างเช่น Intel x86 มีXCHGคำสั่งที่แลกเปลี่ยนเนื้อหาของการลงทะเบียนสองรายการ หลายครั้งที่คอมไพเลอร์จะคิดออกความหมายของฟังก์ชั่นดังกล่าว (มันสลับเนื้อหาของค่าที่ส่งผ่านไป) และสามารถทำการปรับให้เหมาะสมของตัวเองหากจำเป็นดังนั้นพยายามที่จะปรับบางสิ่งบางอย่างที่ไม่สำคัญ ในทางปฏิบัติ เป็นการดีที่สุดที่จะใช้วิธีการที่ชัดเจนเว้นแต่จะมีเหตุผลที่พิสูจน์แล้วว่าทำไมการพูด xorswap ภายในโดเมนปัญหา


18
หากทั้งสองค่าเหมือนกันคุณจะยังคงได้ผลลัพธ์ที่ถูกต้อง a: 0101 ^ 0101 = 0000; b: 0101 ^ 0000 = 0101; a: 0101 ^ 0000 = 0101;
Bobson

1
สิ่งที่ @ GlenH7 พูด ->-1 +1
Bobson

1
คุณยังดูเหมือนจะมีบรรทัดเกี่ยวกับ "เมื่อใช้ xorswap อาจมีอันตรายจากการจัดหาตัวแปรเดียวกับทั้งอาร์กิวเมนต์ของฟังก์ชันซึ่งเลขศูนย์ของตัวแปรดังกล่าวเนื่องจากมันเป็น xor'd ด้วยตัวเองซึ่งเปลี่ยนบิตทั้งหมดเป็นศูนย์" .. นั่นไม่ได้หมายถึงถูกลบออกหรือไม่
Chris

9
@Chris ไม่ตอนแรกฉันเขียนว่าถ้าค่าเหมือนกันa=10, b=10และถ้าคุณทำอย่างxorswap(a,b)นั้นจะได้ผลและไม่ลบตัวแปรที่เป็นเท็จและลบศูนย์ในตอนนี้ แต่ถ้าคุณทำเช่นxorswap(a, a)นั้นก็aจะกลายเป็นศูนย์ซึ่งฉันหมายถึงตอนแรก แต่ก็โง่แล้ว :)
zxcdw

3
มันค่อนข้างมีความเกี่ยวข้องในบางภาษา - อันตรายเล็ก ๆ น้อย ๆ เช่นนี้ทำให้หาข้อผิดพลาดได้ยากในอนาคตเมื่อต้องรับมือกับพอยน์เตอร์สองตัวที่กำหนดให้ชี้ไปยังที่อยู่เดียวกัน 100+ บรรทัดที่คุณไม่เห็น
Drake Clarris

14

กุญแจสำคัญของคำตอบคือคำถาม - "ทำงานเป็นโปรแกรมเมอร์แอสเซมเบลอร์ผู้ประกอบเมนเฟรม" - ในวันก่อนคอมไพเลอร์ เมื่อมนุษย์ตะโกนลงไปพร้อมกับคำแนะนำการประกอบและมือที่สร้างขึ้นมาอย่างแม่นยำสำหรับฮาร์ดแวร์ชิ้นใดชิ้นหนึ่ง (ซึ่งอาจหรืออาจจะไม่ทำงานในคอมพิวเตอร์รุ่นเดียวกัน - ปัญหาเช่นระยะเวลาของฮาร์ดไดรฟ์และหน่วยความจำดรัมนั้นมีผลกระทบต่อรหัส เขียน - อ่านเรื่องราวของเมลหากรู้สึกว่าจำเป็นต้องคิดถึง)

ย้อนกลับไปในอดีตเมื่อวันที่ผ่านมาการลงทะเบียนและความทรงจำทั้งคู่มีความขาดแคลนและกลอุบายใด ๆ ที่ไม่จำเป็นต้องขอไบต์หรือหน่วยความจำอื่นจากสถาปนิกชั้นนำได้ช่วยประหยัดเวลา - ทั้งในการเขียนรหัสและเวลาดำเนินการ

วันเหล่านั้นหายไป กลลวงของการแลกเปลี่ยนสองสิ่งโดยไม่ใช้อันที่สามคือกลลวง หน่วยความจำและรีจิสเตอร์มีมากมายในการคำนวณสมัยใหม่และมนุษย์ไม่ได้เขียนชุดประกอบอีกต่อไป เราได้สอนกลอุบายของเราทั้งหมดให้กับคอมไพเลอร์ของเราและพวกเขาทำงานได้ดีกว่าที่เราทำ โอกาสที่คอมไพเลอร์ได้ทำสิ่งที่ดีกว่าสิ่งที่เราจะทำ ในกรณีส่วนใหญ่บางครั้งเราจำเป็นต้องเขียนชุดประกอบในบิตด้านในของวงวนแน่นด้วยเหตุผลบางอย่าง ... แต่มันไม่ได้เป็นการบันทึกลงทะเบียนหรือคำของหน่วยความจำ

มันอาจจะมีประโยชน์อีกครั้งหากมีใครทำงานในไมโครคอนโทรลเลอร์ที่มีข้อ จำกัด โดยเฉพาะ แต่การปรับการแลกเปลี่ยนให้เหมาะสมนั้นไม่น่าจะเป็นต้นเหตุของปัญหาของคนคนนั้น - การพยายามฉลาดกว่านั้นก็เป็นปัญหามากกว่า


2
การลงทะเบียนไม่ได้มีอยู่จริงในหลายบริบท แม้ว่าโปรเซสเซอร์จะมีการลงทะเบียนที่เพียงพอทุกการลงทะเบียนที่ใช้ใน ISR คือการลงทะเบียนซึ่งจะต้องบันทึกไว้ล่วงหน้าและเรียกคืนหลังจากนั้น หาก ISR ใช้เวลายี่สิบรอบและควรรันทุก ๆ สี่สิบรอบแต่ละรอบพิเศษที่เพิ่มเข้ากับ ISR จะลดประสิทธิภาพของระบบเป็นห้าเปอร์เซ็นต์
supercat

8

มันจะทำงานอย่างไร ใช่.

คุณควรใช้มันหรือไม่? เลขที่

การเพิ่มประสิทธิภาพขนาดเล็กประเภทนี้เหมาะสมถ้า:

  • คุณได้ดูโค้ดที่คอมไพเลอร์สร้างขึ้นสำหรับวิธีการที่ตรงไปตรงมาในการทำสิ่งนี้ (การมอบหมายและชั่วคราว) และตัดสินใจว่าวิธีการของแฮคเกอร์สร้างรหัสได้เร็วขึ้น

  • คุณทำโปรไฟล์แอพของคุณและพบว่าค่าใช้จ่ายของวิธีการที่ตรงไปตรงมานั้นมากกว่าความชัดเจนของรหัส (และทำให้ประหยัดในการบำรุงรักษา)

จนถึงจุดแรกยกเว้นว่าคุณได้ทำการวัดนี้แล้วคุณควรจะไว้วางใจคอมไพเลอร์ เมื่อความหมายของสิ่งที่คุณพยายามทำชัดเจนมีเทคนิคมากมายที่คอมไพเลอร์สามารถทำได้รวมถึงการจัดเรียงการเข้าถึงตัวแปรใหม่เพื่อให้การแลกเปลี่ยนไม่จำเป็นต้องใช้เลย สลับสำหรับชนิดข้อมูลที่กำหนด "เคล็ดลับ" เช่นการสลับ XOR ทำให้ยากขึ้นสำหรับคอมไพเลอร์เพื่อดูว่าคุณกำลังพยายามทำอะไรและทำให้มันไม่สามารถใช้การปรับให้เหมาะสมเช่นนี้ได้น้อยลง

จนถึงจุดที่สองคุณได้อะไรจากความซับซ้อนที่เพิ่มขึ้น แม้ว่าคุณจะวัดผลและพบวิธีการ XOR ที่เร็วขึ้น แต่สิ่งนี้มีผลกระทบเพียงพอที่จะพิสูจน์ให้เห็นถึงวิธีการที่ชัดเจนน้อยลงหรือไม่? คุณรู้ได้อย่างไร?

สุดท้ายคุณควรพิจารณาว่ามีฟังก์ชั่นการสลับมาตรฐานสำหรับแพลตฟอร์ม / ภาษาของคุณหรือไม่เช่น C ++ STL ให้ฟังก์ชั่นการแลกเปลี่ยนเทมเพลตซึ่งจะมีแนวโน้มที่จะปรับให้เหมาะสมที่สุดสำหรับคอมไพเลอร์ / แพลตฟอร์มของคุณ


2

เพื่อนร่วมงานของฉันรายงานว่านี่เป็นกลอุบายพื้นฐานที่เขาสอนในมหาวิทยาลัยที่กำลังศึกษาสำหรับโปรแกรมเมอร์ระบบอัตโนมัติ ระบบดังกล่าวจำนวนมากถูกฝังอยู่ในระบบที่มีทรัพยากร จำกัด และพวกเขาอาจขาดการลงทะเบียนฟรีเพื่อรักษามูลค่าชั่วคราว ในกรณีนั้นการแลกเปลี่ยนที่ยุ่งยาก (หรือแอนะล็อกกับการเพิ่มและการลบ) กำลังได้รับความสำคัญดังนั้นยังคงถูกใช้อยู่

แต่จะต้องระมัดระวังในการใช้งานว่าสถานที่ทั้งสองนี้จะไม่เหมือนกันเพราะในกรณีหลังจะมีค่าทั้งสองเป็นศูนย์ ดังนั้นจึงมักถูก จำกัด เฉพาะกรณีที่ชัดเจนเช่นการแลกเปลี่ยนการลงทะเบียนและตำแหน่งหน่วยความจำ

ด้วย x86 คำสั่ง xchg และ cmpxchg ตอบสนองความต้องการในกรณีส่วนใหญ่ แต่โดยทั่วไป RISC จะไม่ครอบคลุม (ยกเว้น Sparc)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.