Kotlin 提供了幾種用于操作整數各個位(bit) 的運算符。這些操作是由處理器直接支持的,速度快且操作簡單。在底層編程中非常重要,比如設備驅動、低級圖形處理、網絡通信、加密和壓縮等。
盡管計算機通常都有高效的硬件指令來執行算術和邏輯操作,但所有這些操作也都可以通過組合按位操作符、位移操作符和判斷 0 操作來實現。
位運算符(Bitwise Operators)
共有四種位運算符:
-
inv()
:按位非(NOT),即取反或補碼 -
or
:按位或(OR) -
and
:按位與(AND) -
xor
:按位異或(XOR)
這些運算符會一位一位地處理操作數的每一位,并生成一個新的數值。
-
inv()
是一元運算符,它會將每一位的 0 變為 1,1 變為 0(包括符號位也會改變)。 -
or
是二元運算符,按位“或”:只要任意一個操作數為 1,結果就是 1,否則是 0。 -
and
是按位“與”:只有兩個操作數都為 1,結果才是 1,否則是 0。 -
xor
是按位“異或”:當兩個操作數中正好一個為 1 時,結果是 1,否則是 0。
這些運算符不僅可以作用于整數,也可以作用于布爾類型。如果是整數,進行的是位運算;如果是布爾值,進行的是邏輯運算(除了 inv()
不能用于布爾類型)。
示例:按位與、或、異或
val first = 15 // 二進制:1111
val second = 10 // 二進制:1010val bitwiseAnd = first and second // 1111 & 1010 = 1010,結果是 10
val bitwiseOr = first or second // 1111 | 1010 = 1111,結果是 15
val bitwiseXor = first xor second // 1111 ^ 1010 = 0101,結果是 5
示例:按位取反(inv)
val first = 35 // 二進制:0..00100011
val second = -35 // 二進制:1..11011101(補碼)val inverseFirst = first.inv() // ~35 = -36
val inverseSecond = second.inv() // ~-35 = 34
為什么 ~35 = -36
?這是因為 Kotlin 使用**補碼(two’s complement)**來表示整數。
-
對任意正整數
n
,其按位取反是-(n + 1)
。 -
對負數
-n
,其按位取反是n - 1
。
檢查一個數是否能被 2 整除(使用 and
)
val a = 5
val b = 4val bitwiseAndA = a and 1 // 101 & 001 = 001,結果是 1 => 有余數,不能整除
val bitwiseAndB = b and 1 // 100 & 001 = 000,結果是 0 => 沒有余數,可以整除
位移操作符(Bit-shift Operators)
Kotlin 還提供了三種位移操作符:
-
shl
:左移(乘法),低位補零; -
shr
:帶符號右移,高位填符號位(保留正負號); -
ushr
:無符號右移,高位補零(結果永遠為正)。
示例:通過位移實現快速乘除法
var value = 25 // 二進制:0001 1001value = value shl 1 // 左移1位:0011 0010 => 50
value = value shl 2 // 再左移2位:1100 1000 => 200var anotherVal = 14
anotherVal = anotherVal shr 1 // 右移1位:0111 => 7
我們可以總結出:
var newVal = 25newVal = newVal shl 1 // 25 * 2^1 = 50
newVal = newVal shl 3 // 50 * 2^3 = 400
newVal = newVal shr 2 // 400 / 2^2 = 100
示例:使用位移求區間中點
val left = 10
val right = 20val mid = (left + right) shr 1 // 結果是 15
與 (left + right) / 2
相同,但位移方式更快。
示例:shr
與 ushr
的區別
val number1 = 5
val number2 = -5val shrNumber1 = number1 shr 1 // 0101 → 0010,結果是 2
val ushrNumber1 = number1 ushr 1 // 同上,結果是 2
val shrNumber2 = number2 shr 1 // 保留符號,結果是 -3
val ushrNumber2 = number2 ushr 1 // 補零,結果是 2147483645
-
shr
會根據符號保留符號位。 -
ushr
總是左邊補 0,所以負數也變為正數。
Kotlin 1.6 新增:位旋轉
val a = 4val shiftRight = a.rotateRight(1) // 0100 → 0010,結果是 2
val shiftLeft = a.rotateLeft(1) // 0100 → 1000,結果是 8
val b = 3val shiftLeft = b.rotateLeft(1) // 0011 → 0110,結果是 6
val shiftRight = b.rotateRight(1) // 0011 → 1..0001,結果是 -2147483647
rotateRight 會把最高位 1 移到符號位(第 31 位),結果變成負數。
運算優先級
Kotlin 中,位運算符和位移運算符的優先級低于加減乘除:
優先級(從高到低) | 運算符例子 |
---|---|
括號 | (expr) |
后綴自增自減 | expr++ , expr-- |
前綴正負、自增自減 | -expr , ++expr , --expr |
乘、除、模 | * , / , % |
加減 | + , - |
賦值及其組合 | = , += , -= , *= 等 |
位運算和位移 | and , or , xor , shl , shr , ushr |
位運算符之間是從左到右執行的。 |
例如:
val mid = left + right shr 1
無需加括號,是因為 +
的優先級高于 shr
,相當于:
val mid = (left + right) shr 1
總結
在本節中,我們學習了如何對整數的位進行操作,理解了位運算與一些算術運算之間的對應關系:
-
位運算符:逐位處理。
-
位移運算符:可以整體左移或右移一整串位。
雖然位運算看起來稍顯復雜,但這是理解底層編程和高效計算的基礎。