您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“Golang中的位操作實例代碼分析”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
在計算機(jī)內(nèi)存昂貴,處理能力有限的美好舊時光里,用比較黑客范的位運算方式去處理信息是首選方式(某些情況下只能如此)。時至今日,直接使用位運算仍然是很多計算領(lǐng)域中不可或缺的部分,例如底層系統(tǒng)編程,圖形處理,密碼學(xué)等。
Go 編程語言支持以下按位運算符:
& bitwise AND | bitwise OR ^ bitwise XOR &^ AND NOT << left shift >> right shift
本文的余下部分詳述了每個操作符以及它們?nèi)绾问褂玫陌咐?/p>
在 Go 中, &
運算符在兩個整型操作數(shù)中執(zhí)行按位 AND
操作。AND
操作具有以下屬性:
Given operands a, b AND(a, b) = 1; only if a = b = 1 else = 0
AND
運算符具有選擇性的把整型數(shù)據(jù)的位清除為 0 的好的效果。 例如,我們可以使用 &
運算符去清除(設(shè)置)最后 4 個最低有效位(LSB)全部為 0 。
func main() { var x uint8 = 0xAC // x = 10101100 x = x & 0xF0 // x = 10100000 }
所有的位運算都支持簡寫的賦值形式。 例如,前面的例子可以重寫為如下。
func main() { var x uint8 = 0xAC // x = 10101100 x &= 0xF0 // x = 10100000 }
另外一個巧妙的技巧是:你可以用 &
操作去測試一個數(shù)字是奇數(shù)還是偶數(shù)。原因是當(dāng)一個數(shù)字的二進(jìn)制的最低位是 1 的時候,那他就是奇數(shù)。我們可以用一個數(shù)字和 1 進(jìn)行 &
操作,然后在和 1 做 AND
運算,如果的到的結(jié)果是 1 ,那么這個原始的數(shù)字就是奇數(shù)
import ( "fmt" "math/rand" ) func main() { for x := 0; x < 100; x++ { num := rand.Int() if num&1 == 1 { fmt.Printf("%d is odd\n", num) } else { fmt.Printf("%d is even\n", num) } } }
在 Playground 上運行上面的例子
|
對其整型操作數(shù)執(zhí)行按位或
操作?;叵胍幌?code>或操作符具備以下性質(zhì):
Given operands a, b OR(a, b) = 1; when a = 1 or b = 1 else = 0
我們可以利用按位或
操作符為給定的整數(shù)有選擇地設(shè)置單個位。例如,在如下示例中我們使用按位或
將示例數(shù)(從低位到高位(MSB))中的第 3 ,第 7 和第 8 位置為 1 。
func main() { var a uint8 = 0 a |= 196 fmt.Printf("%b", a) } // 打印結(jié)果 11000100 ^^ ^
練習(xí)場中可運行范例。
在使用位掩碼技術(shù)為給定的整型數(shù)字設(shè)置任意位時,或
運算非常有用。例如,我們可以擴(kuò)展之前的程序為變量 a
存儲的值設(shè)置更多的位。
func main() { var a uint8 = 0 a |= 196 a |= 3 fmt.Printf("%b", a) } // 打印結(jié)果 11000111
在練習(xí)場中可以運行范例。
在前面的程序里,不僅要按位設(shè)置十進(jìn)制的 196,而且要設(shè)置低位上的十進(jìn)制 3。我們還可以繼續(xù)(或
上更多的值)設(shè)置完所有的位。
現(xiàn)在,回顧一下 AND(a, 1) = a 當(dāng)且僅當(dāng) a = 1
。 我們可以利用這個特性去查詢其設(shè)置位的值。例如,在上述代碼中 a & 196
會返回 196 是因為這幾位的值在 a
中確實都存在。所以我們可以結(jié)合使用 OR
和 AND
運算的方式來分別設(shè)置和讀取某位的配置值。.
接下來的源碼片段演示了這個操作。函數(shù) procstr
會轉(zhuǎn)換字符串的內(nèi)容。它需要兩個參數(shù):第一個, str
,是將要被轉(zhuǎn)換的字符串,第二個, conf
,是一個使用位掩碼的方式指定多重轉(zhuǎn)換配置的整數(shù)。
const ( UPPER = 1 // 大寫字符串 LOWER = 2 // 小寫字符串 CAP = 4 // 字符串單詞首字母大寫 REV = 8 // 反轉(zhuǎn)字符串 ) func main() { fmt.Println(procstr("HELLO PEOPLE!", LOWER|REV|CAP)) } func procstr(str string, conf byte) string { // 反轉(zhuǎn)字符串 rev := func(s string) string { runes := []rune(s) n := len(runes) for i := 0; i < n/2; i++ { runes[i], runes[n-1-i] = runes[n-1-i], runes[i] } return string(runes) } // 查詢配置中的位操作 if (conf & UPPER) != 0 { str = strings.ToUpper(str) } if (conf & LOWER) != 0 { str = strings.ToLower(str) } if (conf & CAP) != 0 { str = strings.Title(str) } if (conf & REV) != 0 { str = rev(str) } return str }
在 Playground上面運行代碼.
上面的 procstr("HELLO PEOPLE!", LOWER|REV|CAP)
方法會把字符串變成小寫,然后反轉(zhuǎn)字符串,最后把字符串里面的單詞首字母變成大寫。這個功能是通過設(shè)置 conf
里的第二,三,四位的值為 14 來完成的。然后代碼使用連續(xù)的 if 語句塊來獲取這些位操作進(jìn)行對應(yīng)的字符串轉(zhuǎn)換。
在 Go 中 按位 異或
操作是用 ^
來表示的。 異或
運算符有如下的特點:
Given operands a, b XOR(a, b) = 1; only if a != b else = 0
異或
運算的這個特性可以用來把二進(jìn)制位的一個值變成另外一個值。舉個例子,給到一個 16 進(jìn)制的值,我們可以使用以下代碼切換前8位(從 MSB 開始)的值。
func main() { var a uint16 = 0xCEFF a ^= 0xFF00 // same a = a ^ 0xFF00 } // a = 0xCEFF (11001110 11111111) // a ^=0xFF00 (00110001 11111111)
在前面的代碼片段中,與 1 進(jìn)行異或的位被翻轉(zhuǎn)(從 0 到 1 或從 1 到 0)。異或
運算的一個實際用途,例如,可以利用 異或
運算去比較兩個數(shù)字的符號是否一樣。當(dāng) (a ^ b) ≥ 0
(或相反符號的 (a ^ b) < 0
)為 true
的時候,兩個整數(shù) a,b 具有相同的符號,如下面的程序所示:
func main() { a, b := -12, 25 fmt.Println("a and b have same sign?", (a ^ b) >= 0) }
在 Go 的 Playground運行代碼。
當(dāng)執(zhí)行上面這個程序的時候,將會打印出:a and b have same sign? false
。在 Go Playground 上修改程序里 a ,b 的符號,以便看到不同的結(jié)果。
不像其他語言 (c/c++,Java,Python,Javascript,等), Go 沒有專門的一元取反位運算符。取而代之的是,XOR
運算符 ^
,也可作為一元取反運算符作用于一個數(shù)字。對于給定位 x,在 Go 中 x = 1 ^ x 可以翻轉(zhuǎn)該位。在以下的代碼段中我們可以看到使用 ^a
獲取變量 a
的取反值的操作。
func main() { var a byte = 0x0F fmt.Printf("%08b\n", a) fmt.Printf("%08b\n", ^a) } // 打印結(jié)果 00001111 // var a 11110000 // ^a
在練習(xí)場中可以運行范例。
&^
操作符意為 與非
,是 與
和 非
操作符的簡寫形式,它們定義如下。
Given operands a, b AND_NOT(a, b) = AND(a, NOT(b))
如果第二個操作數(shù)為 1 那么它則具有清除第一個操作數(shù)中的位的趣味特性。
AND_NOT(a, 1) = 0; clears a AND_NOT(a, 0) = a;
接下來的代碼片段使用 AND NOT
操作符,將變量值1010 1011
變?yōu)?1010 0000
,清除了操作數(shù)上的低四位。
func main() { var a byte = 0xAB fmt.Printf("%08b\n", a) a &^= 0x0F fmt.Printf("%08b\n", a) } // 打?。? 10101011 10100000
在練習(xí)場中運行范例。
與其他 C 的衍生語言類似, Go 使用 <<
和 >>
來表示左移運算符和右移運算符,如下所示:
Given integer operands a and n, a << n; shifts all bits in a to the left n times a >> n; shifts all bits in a to the right n times
例如,在下面的代碼片段中變量 a
(00000011
)的值將會左移位運算符分別移動三次。每次輸出結(jié)果都是為了說明左移的目的。
func main() { var a int8 = 3 fmt.Printf("%08b\n", a) fmt.Printf("%08b\n", a<<1) fmt.Printf("%08b\n", a<<2) fmt.Printf("%08b\n", a<<3) } // 輸出的結(jié)果: 00000011 00000110 00001100 00011000
在 Playground 運行代碼
注意每次移動都會將低位右側(cè)補(bǔ)零。相對應(yīng),使用右移位操作符進(jìn)行運算時,每個位均向右方移動,空出的高位補(bǔ)零,如下示例 (有符號數(shù)除外,參考下面的算術(shù)移位注釋)。
func main() { var a uint8 = 120 fmt.Printf("%08b\n", a) fmt.Printf("%08b\n", a>>1) fmt.Printf("%08b\n", a>>2) } // 打印: 01111000 00111100 00011110
在 練習(xí)場中可以運行范例。
可以利用左移和右移運算中,每次移動都表示一個數(shù)的 2 次冪這個特性,來作為某些乘法和除法運算的小技巧。例如,如下代碼中,我們可以使用右移運算將 200
(存儲在變量 a 中)除以 2 。
func main() { a := 200 fmt.Printf("%d\n", a>>1) } // 打印: 100
在 練習(xí)場 中可以運行范例。
或是通過左移 2 位,將一個數(shù)乘以4:
func main() { a := 12 fmt.Printf("%d\n", a<<2) } // 打?。? 48
在 練習(xí)場 中可以運行范例。
位移運算符提供了有趣的方式處理二進(jìn)制值中特定位置的值。例如,下列的代碼中,|
和 <<
用于設(shè)置變量 a
的第三個 bit 位。
func main() { var a int8 = 8 fmt.Printf("%08b\n", a) a = a | (1<<2) fmt.Printf("%08b\n", a) } // prints: 00001000 00001100
可以在 練習(xí)場 中運行代碼示例。
或者,您可以組合位移運算符和 &
測試是否設(shè)置了第n位,如下面示例所示:
func main() { var a int8 = 12 if a&(1<<2) != 0 { fmt.Println("take action") } } // 打印: take action
在 練習(xí)場中運行代碼。
使用 &^
和位移運算符,我們可以取消設(shè)置一個值的某個位。例如,下面的示例將變量 a 的第三位置為 0 :
func main() { var a int8 = 13 fmt.Printf("%04b\n", a) a = a &^ (1 << 2) fmt.Printf("%04b\n", a) } // 打印: 1101 1001
在 練習(xí)場 中運行代碼。
當(dāng)要位移的值(左操作數(shù))是有符號值時,Go 自動應(yīng)用算術(shù)位移。在右移操作期間,復(fù)制(或擴(kuò)展)二進(jìn)制補(bǔ)碼符號位以填充位移的空隙。
“Golang中的位操作實例代碼分析”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。