位操作學習的一些困惑

王小東大將軍發表於2017-06-20

 點選開啟連結 《位操作基礎篇之位操作全面總結


對於移位操作,在微軟的VC6.0和VS2008編譯器都是採取算術稱位即算術移位操作,算術移位是相對於邏輯移位,它們在左移操作中都一樣,低位補0即可,但在右移中邏輯移位的高位補0而算術移位的高位是補符號位。如下面程式碼會輸出-4和3。

#include <stdio.h>  
#include <math.h>   
int main(){  
	int a = -15, b = 15;
	printf("%d %d\n", a >> 2, b >> 2);
     return 0;  
}
因為15=0000 1111(二進位制),右移二位,最高位由符號位填充將得到0000 0011即3。-15 = 1111 0001(二進位制),右移二位,最高位由符號位填充將得到1111 1100即-4。



變換符號

變換符號就是正數變成負數,負數變成正數。

如對於-11和11,可以通過下面的變換方法將-11變成11

      1111 0101(二進位制) –取反-> 0000 1010(二進位制) –加1-> 0000 1011(二進位制)

同樣可以這樣的將11變成-11

      0000 1011(二進位制) –取反-> 1111 0100(二進位制) –加1-> 1111 0101(二進位制)

因此變換符號只需要取反後加1即可。完整程式碼如下

#include <stdio.h>
int SignReversal(int a)
{
	return ~a + 1;
}
int main()
{
	printf("對整數變換符號 --- by MoreWindows( http://blog.csdn.net/MoreWindows )  ---\n\n");
	int a = 7, b = -12345;
	printf("%d  %d\n", SignReversal(a), SignReversal(b));
	return 0;
}

求絕對值

位操作也可以用來求絕對值,對於負數可以通過對其取反後加1來得到正數。對-6可以這樣:

      1111 1010(二進位制) –取反->0000 0101(二進位制) -加1-> 0000 0110(二進位制)

來得到6。

因此先移位來取符號位,int i = a >> 31;要注意如果a為正數,i等於0,為負數,i等於-1。然後對i進行判斷——如果i等於0,直接返回。否之,返回~a+1。完整程式碼如下:

//by MoreWindows( http://blog.csdn.net/MoreWindows )
int my_abs(int a)
{
	int i = a >> 31;
	return i == 0 ? a : (~a + 1);
}

現在再分析下。對於任何數,與0異或都會保持不變,與-1即0xFFFFFFFF異或就相當於取反。因此,a與i異或後再減i(因為i為0或-1,所以減i即是要麼加0要麼加1)也可以得到絕對值。所以可以對上面程式碼優化下:

//by MoreWindows( http://blog.csdn.net/MoreWindows )
int my_abs(int a)
{
	int i = a >> 31;
	return ((a ^ i) - i);
}





相關文章