題目:一個數組中有多個整數,其中只有一個沒有重複過,求出該數:算法
考慮使用異或操做幫助實現。數組
int AppearOnce(int data[], int length) { int i; int once = 0; for (i = 0; i < length; i++) { once ^= data[i]; } return once; }
隱含原理,只有一個沒有重複過,其餘的都重複過,說明數的個數爲2N+1函數
N對相同的數異或,結果爲0,如:性能
a^b^a^b=0;this
0^x=x;spa
0跟任何數異或仍是自身。rest
題目:用位運算實現求絕對值-有效避開if-else判斷code
By SmartPtr(http://www.cppblog.com/SmartPtr/)
orm
通常狀況下,若是要咱們寫一個求絕對值的函數,咱們的實現頗有可能會是這樣:對象
也就是說咱們會用到一個if-else判斷來決定是否反轉符號位。在3D遊戲軟件,或一些對性能要求比較高的底層系統中,當大規模的求絕對值時,這個if-else結構會帶來性能上的損失,那麼,如何來消除if-else結構呢?或許會有人說,咱們能夠用三元操做符啊:
可是事實上這是換湯不換藥,由於其實質上仍是存在if-else的判斷的(這應該能夠從反彙編代碼中看出來)。
咱們是經過位操做來消除if-else判斷來求絕對值。
由於使用位操做,咱們不得不考慮咱們操做對象類型的字節數,下面我將以都是4字節得float和int爲例實現位操做求絕對值。
首先,咱們有必要了解一下float與int在計算機中的內部表示方法。
1) float: float即單精度浮點數,"浮點數"由兩部分組成,即尾數和階碼。在浮點表示方法中,小數點的位置是浮動的,階碼可取不一樣的數值。爲了便於計算機中小數點的表示,規定將浮點數寫成規格化的形式,即尾數的絕對值大於等於0.1而且小於1,從而惟一規定了小數點的位置。尾數的長度將影響數的精度,其符號將決定數的符號。浮點數的階碼至關於數學中的指數,其大小將決定數的表示範圍。一個浮點數在計算機中的表現形式以下:
尾數符號 階碼 尾數有效值
S E M
s是符號位,佔1位,爲0表示正。
M尾數:對於32位浮點數來講,佔用23位。E是階碼,佔用8位。
2) int: 用補碼錶示,由於正整數的原碼,反碼,補碼都是同樣的,而負整數的補碼則是經過原碼->反碼->補碼轉換來的,因此,-3與3的內部表示位差異不單單在符號位
其次,這裏先列出兩個在代碼中用到的宏:
#define INV_SIGN_BIT 0x7fffffff //用來反轉符號位
#define USE_ASM //是否使用匯編代碼
1 float求絕對值
知道了float的內部表示,咱們知道要求其絕對值,只要將其尾數符號位置0便可。這又有下面兩種方法:
1)與:經過和INV_SIGN_BIT相"與"而將符號位置0
float absFloat(float a)
{
int p=*((int*)&a);
int out=(p)&0x7fffffff;
return *((float*)&out);
}
注:
1)這裏將float轉化成int的緣由是C語言不支持float的移位操做。
2)移位:經過先邏輯左移1位,再邏輯右移一位將符號位置0
注:
1)這裏使用unsigned int的緣由是C語言的移位操做對有符號數是算術移位,對無符號數是邏輯移位。而咱們須要的是邏輯移位
2 int求絕對值
由於整型的內部表示是反碼,咱們不能簡單的經過符號位置0求絕對值,下面的算法很好的解決了這個問題:
注:
1)對於代碼
temp = temp >> 31;
out = out ^ temp;
out = out - temp;
若是iNum是正數:
temp = temp >> 31; //temp = 0
out = out ^ temp; //與0異或不變
out = out - temp; //減0不變
out的結果就是iNum,即正數的絕對值是其自己,沒問題
若是iNum是負數:
temp = temp >> 31; //temp = oxffffffff
out = out ^ temp; //out爲iNum求反 (利用異或取反)
out = out - temp; // 此時temp = 0xffffffff = -1, 因此out = out + 1
把一個負數的補碼連符號位求反後再加1,就是其絕對值了。好比對於-2來講:
原碼 | 反碼 | 補碼 | 補碼全求反 | 再加1 | 備註 |
10000010 | 11111101 | 11111110 | 00000001 | 00000010 |
你們能夠看到第一個與最後一個數只有符號位不一樣,也就實現了求其絕對值。
(之前作過的一道題目,對一個數[y]補,獲得其[-y]補:
int negative(int a)//取補碼,咱們輸入x,會輸出-x。
{
return add(~a,1);
}
)
對於其餘類型的數據求絕對值,應該 都是大同小異的。這裏就再也不列舉。