標籤:
異或(^) 跟 按位與(&)、按位或(|) 一樣是一個位元運算符,運算速度自然是很快的。
一般的,它似乎沒什麼用途。我所知道的它最多就用來加加密,用來交換數值。這裡說說使用異或交換數值的一些利弊。
優點: 不需要使用中間變數
一般的交換a,b的值,是使用第三方變數temp
temp = a;a = b;b = temp;
可是有一天突然發現了有異或交換數值的方法,這個方法不需要使用第三方變數
a = a ^ b;b = a ^ b;a = a ^ b;
這個方法的寫法也很簡單:複製3行a = a ^ b,再把第二行的a換成b,我簡直太愛這個方法了,只要能有用到的地方,我都考慮用這個方法,也沒有遇到任何問題。
可是今天看到了一篇部落格《用異或交換兩個整數的陷阱》,試著要分析了一下,分析如下:
假設a,b數值相等,都等於x,值寫在括弧裡
a = a(x) ^ b(x); —> a=0, b=xb = a(0) ^ b(x); —> a=0, b=xa = a(0) ^ b(x); —> a=x, b=x
經過這麼3步,最後的結果很正常,並沒有如他所說是0
不過,再仔細看,是我理解錯了,他的意思是,如果a和b是指向同一個地址的數,即a,b是同一個變數,那麼就會出錯
a = a(x) ^ a(x) --> a = 0a = a(0) ^ a(0) --> a = 0a = a(0) ^ a(0) --> a = 0
所以使用異或交換數值需要注意這個陷阱。
缺點: 並不能加快程式運行
我一直覺得異或運算速度快嘛,交換數值肯定也快,然而確實是這樣嗎?
我在網上又找到了另一篇部落格《用異或來交換兩個變數效率分析》,這裡引用部落格原文的一些觀點:
1. 這個所謂的“技巧”在現代的機器上只會更慢(我甚至懷疑它從來就不可能比原始辦法快)。原始辦法是兩次記憶體讀和寫,這個"技巧"是六讀三寫加三次異或(或許編譯器可以最佳化成兩讀三寫加三次異或)。
2. 同樣也不能節省記憶體,因為中間變數 tmp 通常會是寄存器(稍後有彙編代碼供分析)。就算它在函數的局部堆棧(stack)上,反正棧已經開在那兒了,也沒有進一步的函數調用,根本節約不了一丁點記憶體。
3. 相反,由於計算步驟較多,會使用更多的指令,編譯後的機器碼長度會增加。(這不是什麼大問題,短的代碼不一定快,後面有另外一個例子。)
具體的分析可以去看看他的部落格。
So 看上去使用異或交換數值是弊大於利,它的優點似乎是微不足道的,現在的硬體那麼發達,節約一個變數空間並沒有多大意義,倒不如以這點小小的空間換取時間來得值。知道了這樣的事實,我就不再考慮異或來交換數值了,老老實實的使用古老的第三方變數就好了。
異或交換數值的分析