位操作

位操作是程式設計中對位陣列或二進位制數的一元和二元操作。在許多古老的微處理器上，位運算比加減運算略快，通常位運算比乘除法運算要快很多。在現代架構中，位運算的運算速度通常與加法運算相同，但是通常功耗較小，因為資源使用減少。位運算子.下面的解釋中，任何二進位制位的表示都從右側每位上都是0。取反.取反是一元運算子，對一個二進位制數的每一位執行邏輯反操作。使數字1成為0，0成為1。例如：NOT 0111= 1000NOT 10101011 (十進位制 171)= 01010100 (十進位制 84)結果等於該值的補碼減一。如果使用補碼算術，則 codice_1。對於無符號整數，數的按位補碼是其在無符號整數範圍的中點另一邊的“映象”。例如，對於8位無符號整數，codice_2，可以在圖上將其視覺化為一條向下的線，相當於把從 0 到 255 遞增的範圍，“翻轉”到從 255 到 0 遞減的範圍。一個簡單而有說明性的使用例子是反轉灰度影象，其中每個畫素儲存為無符號整數。許多程式設計語言”運算子不同。在C++中，邏輯非將數字整體看做一個布林型別——將真值轉化為假，將假值轉化為真；而C語言將0轉化為1，將非零值轉化為0。“邏輯非”並不是一個位操作。按位或.按位或處理兩個長度相同的二進位制數，兩個相應的二進位中只要有一個為1，該位的結果值就為1。例如-{}- 0101OR 0011= 0111在C類程式設計語言中，按位或運算子是"|"。這一運算子需要與邏輯或運算子區別開來。按位或能夠將每一位看做旗標；在二進位制數中的每一位可以表示不同的布林變數。應用按位或操作可以將二進位制數的某一位設為1。例如-{}-0010能夠看做包含4個旗標的組合。第1，2，4旗標為0；第3個旗標為1。利用按位或可以將第1個旗標設定為1，而其他旗標不變。-{}- 0010OR 1000= 1010這一技巧通常用來儲存程式中的大量布林變數。按位異或.按位異或運算，對等長二進位制模式或二進位制數的每一位執行邏輯異或操作。操作的結果是如果某位不同則該位為1，否則該位為0。例如0101XOR 0011= 0110在類C語言中，按位異或運算子是"codice_5"。組合語言的程式設計師們有時使用按位異或運算作為將暫存器的值設為0的捷徑。用值的自身對其執行按位異或運算將得到0。並且在許多架構中，與直接載入0值並將它儲存到暫存器相比，按位異或運算需要較少的中央處理單元時鐘週期。按位異或也可以用於在位元集合中切換旗標。給出一個位元模式，0010第一和第三位能夠透過按位異或運算使用同時切換。0010XOR 1010= 1000這一技巧可用於操作表示布林變數的位元模式。按位與.按位與處理兩個長度相同的二進位制數，兩個相應的二進位都為1，該位的結果值才為1，否則為0。例如：0101AND 0011= 0001此操作可以被用來檢查一個特定的位是1還是0。例如，給定一個二進位制模式0011，我們用按位與和一個僅在第二位為1的二進位制模式來確定第二位是否為1：0011 (十進位制 3)AND 0010 (十進位制 2)= 0010 (十進位制 2)因為結果0010是非零的，所以我們知道原模式中的第二位是1。這通常被稱為"位掩碼"。按位與可用於清除暫存器的選定位，其中每個位代表一個單獨的布林狀態。 這種技術是一種使用盡可能少的記憶體來儲存大量布林值的有效方法。例如，0110可以被認為是一組四個旗標，其中第一個和第四個旗標是清除 (0)，第二和第三個旗標是設定 (1)。 第三個旗標可以透過按位與僅在第三位具有零的模式來清除：0110 (十進位制 6)AND 1011 (十進位制 11)= 0010 (十進位制 2)因為這條性質，透過查詢最低位的值檢查一個二進位制數的奇偶性變得容易。用以上的例子：0110 (十進位制 6)AND 0001 (十進位制 1)= 0000 (十進位制 0)因為6按位與1是0，6可以被2整除，所以6是偶數。在類C語言中，按位與用'&amp;'表示。數學等價物.假設formula_1，對於非負整數，按位運算可以被寫成如下形式：formula_2所有二元邏輯運算子的真值表.兩個有16種可能的真值函式；這定義了一個真值表。這是兩位 P 和 Q 的按位等效運算：移位.移位是一個二元運算子，用來將一個二進位制數中的每一位全部都向一個方向移動指定位，溢位的部分將被捨棄，而空缺的部分填入一定的值。在類C語言中，左移使用兩個小於符號"«"表示，右移使用兩個大於符號"»"表示。位定址.如果暫存器的寬度，則移位操作會促使從位元組到位的定址策略。因此，進位制的標準數字書寫中，取“左”和“右”方向，使得左移增加數字的值，右移減少數字的值——如果先讀取左側數位，這就是大端位元組序。忽略暫存器兩端的邊界效應，算術和邏輯移位操作的行為相同，移動 8 位將位模式轉移 1 個位元組位置，方式如下：算術移位.在"算術移位"中，溢位兩端的位都被丟棄。算術左移中，右側補上0；算術右移中，左側補上，以保持原數的符號不變。這個例子使用一個8位暫存器，解釋為補碼：00010111 (十進位制 +23) LEFT-SHIFT= 00101110 (十進位制 +46)10010111 (十進位制 −105) RIGHT-SHIFT= 11001011 (十進位制 −53)在第一種情況下，最左邊的數字被移到暫存器的末尾，新的 0 被移到最右邊的位置。 在第二種情況下，最右邊的 1 被移出，一個新的 1 被複制到最左邊的位置，保留了數字的符號。 多個移位有時會縮短為一個移位，減少了幾位。 例如：00010111 (decimal +23) LEFT-SHIFT-BY-TWO= 01011100 (decimal +92)算術左移"n"位等價與乘以2"n" (前提值沒有整數溢位）。一個補碼的值算術右移"n" 位等價與除以2"n" 下取整。如果二進位制數被視為一的補碼，則相同的右移運算會導致除以2"n" 和向零舍入。邏輯移位.應用"邏輯移位"時，移位後空缺的部分全部填0。因此，邏輯左移和算術左移完全相同。但是，由於邏輯右移將值 0 位插入最高位，而不是複製符號位，因此它適用於無符號二進位制數，而算術右移適用於有符號補碼二進位制數。-{}- 0001« 3= 1000-{}- 1010» 2= 0010迴圈移位.另一種移位是迴圈移位。旋轉.在此操作中，有時稱為"迴圈無進位"，位被“旋轉”，就好像暫存器的左端和右端連線在一起一樣。 在左移期間移入右側的值是從左側移出的任何值，右移操作時反之亦然。 如果需要保留所有現有位，這很有用，並且它經常用於數字密碼學中。進位旋轉."進位旋轉"是一種旋轉操作的變種，其中移入成為進位標志的新值。一個簡單的"進位旋轉"可以模擬邏輯和算術移位，只需提前設定好進位標誌。比如，如果進位標誌是0，那麼codice_6是邏輯右移一位；如果進位標誌裡是符號位的複製，那麼codice_6是算術右移一位。因為這些原因，一些微控制器像低端PIC微控制器只有"旋轉"和"進位旋轉"，並不擔心算術或邏輯移位。當對大於處理器的本機字長的數字執行移位時，進位旋轉特別有用，因為如果一個大數儲存在兩個暫存器中，從第一個暫存器的一端移出的位必須在另一端進入第二個暫存器。使用迴圈進位時，該位在第一次移位期間“儲存”在進位標誌中，準備在第二次移位期間移入而無需任何額外準備。在高階語言中.類C語言和Python.在類C語言和Python中，邏輯移位運算子是左移“codice_8”和右移“codice_9”。移位的位置數作為運算子的第二個引數給出。例如，x = y « 2;將codice_10賦值為codice_11左移兩位的結果，其等價於乘以四。移位可能導致實現定義的行為或未定義行為，因此在使用它們時必須小心。 在 C 和 C++ 中，移位大於或等於字大小的位數是未定義的行為。右移負值是實現定義的，但良好的編碼實踐不建議這樣做；如果結果無法在結果型別中表示，則左移有符號值的結果是未定義的。在 C# 中，當第一個運算元是整形或長整形時，右移是算術移位。 如果第一個運算元是無符號整形或無符號長整形，則右移是邏輯移位。Java.JAVA中有一個特有的無符號右移運算子“»&gt;”。此操作將忽略運算元的符號，同樣的還有“»&gt;=”。JavaScript.JavaScript使用按位運算將兩個或多個數字中的每一個求值為 1 或 0。Pascal.在 Pascal 及其所有方言中，邏輯左移運算子和右移運算子分別是“codice_12”和“codice_13”。 即使對於有符號整數， codice_13 的行為也類似於邏輯移位，並且不會複製符號位。 要移動的位置數作為第二個引數給出。 例如，下面將 y 左移兩位的結果賦值給 x：x := y shl 2;應用.位運算是必要的，尤其是在裝置驅動程式、低階圖形、通訊協議包組裝和解碼等低階程式設計中。儘管機器通常具有執行算術和邏輯運算的有效內建指令，但所有這些運算都可以透過以各種方式組合按位運算子和零測試來執行。例如，這裡是的虛擬碼實現，展示瞭如何僅使用位移和加法將兩個任意整數 codice_15 和 codice_16相乘：c ← 0while b ≠ 0if (b and 1) ≠ 0c ← c + aleft shift a by 1right shift b by 1return c另一個例子是加法的虛擬碼實現，展示瞭如何使用按位運算子和零測試計算兩個整數 codice_15 和 codice_16 的和：while a ≠ 0c ← b and ab ← b xor aleft shift c by 1a ← creturn b