按位取反運計算方法

jackytse_發表於2012-10-29

讀本文前請首先搞懂  “反碼”,“取反”,“按位取反(~)”,這3個概念是不一樣的。

取反:0變1,1變0

反碼:正數的反碼是其本身,對於負數其符號位不變其它各位取反(0變1,1變0)

按位取反(~): 這將是下面要討論的。


“~”運算子在c、c++、java、c#中都有,之前一直沒有遇到這個運算子。

要弄懂這個運算子的計算方法,首先必須明白二進位制數在記憶體中的存放形式,二進位制數在記憶體中是以補碼的形式存放的。

另外正數和負數的補碼不一樣,正數的補碼、反碼都是其本身,既:

正數9:

原碼為: 0000 1001

補碼為: 0000 1001

反碼為: 0000 1001


再例如: -2 

求原碼: 1111 0010 (前面4個1表示符號位)

求反碼: 1111 1101 (符號位不變,其餘各位求反)

求補碼: 1111 1110 (符號位不變,末位+1)

所以-2在記憶體中存放為: 1111 1110


-------------------------------------------------------------------------------------------------

弄懂了上述情況後,如何計算就好辦了

假設要對正數9按位取反——> (~9),計算步驟如下,

原碼為 0000 1001,

反碼為 0000 1001,

補碼為 0000 1001,

對其取反 1111 0110(符號位一起進行取反,這不是反碼更加不是最終結果,只是補碼的取反僅此而已

我們還需要把他轉換成原碼,因為是負數所以進行負數補碼到原碼的逆運算

先減1得反碼: 1111 0101

取反得原碼:1111 1010,(反碼和原碼是一個相對的概念,對反碼取反就是原碼。取反過程符號位是不變的哦)

前面4個1是符號位,1是負數,既得十進位制:-10

不知道說的明不明白,這裡步驟就是:

1. 先對正數求補碼

2. 然後對補碼取反,包括符號位

3. 最後進行一個補碼求原碼的過程,一定要搞清概念啊。


-------------------------------------------------------------------------------------------------

下面我們再反推計算 (~ -10)

-10的原碼:1111 1010 

-10的反碼:1111 0101 (符號位不變)

-10的補碼:1111 0110 (符號位不變,末位+1)

補碼取反:0000 1001 (符號位一起取反)

這是一個正數,那麼我們對其求原碼就可得到最終結果?

因為正數的補碼,反碼,原碼都是一樣的 那我們的最終結果是 0000 1001 ,十進位制是 9,這與我們前面推算出的結果吻合。


-------------------------------------------------------------------------------------------------

最後一個有趣的事實是:

1. 所有正整數的按位取反是其本身+1的負數

2. 所有負整數的按位取反是其本身+1的絕對值

3. 零的按位取反是 -1(0在數學界既不是正數也不是負數) 

	// 測試-1億 到 1億的所有整數  :)
	for (int i = 0; i <= 100000000;++i)
	{
		if (~i != -(i+1) )
		{
			__asm { cli	}			// 彙編中斷指令
		}

		if (i && ~(-i) != abs((-i)+1) )
		{
			__asm { cli	}
		}
	}



相關文章