人妻精品在线观看一区二区三区,蜜臀av精品一区二区三区网站,中文一区二区三区亚洲欧美,熟女人妇精品一区二区,人妻av在线观看视频,欧美日韩国产三级精品网站,黄色免费网站直接进入,超碰公开福利正在播放,国产毛片乡下农村妇女毛片

淺析Golang中的的位操作(按位運(yùn)算符)-全球熱門

來源:php中文網(wǎng) | 2023-02-24 20:58:37 |

在計(jì)算機(jī)內(nèi)存昂貴,處理能力有限的美好舊時(shí)光里,用比較黑客范的位運(yùn)算方式去處理信息是首選方式(某些情況下只能如此)。時(shí)至今日,直接使用位運(yùn)算仍然是很多計(jì)算領(lǐng)域中不可或缺的部分,例如底層系統(tǒng)編程,圖形處理,密碼學(xué)等。

Go 編程語言支持以下按位運(yùn)算符:


(相關(guān)資料圖)

&   bitwise AND |   bitwise OR ^   bitwise XOR&^   AND NOT<<   left shift>>   right shift

本文的余下部分詳述了每個(gè)操作符以及它們?nèi)绾问褂玫陌咐?/p>

& 運(yùn)算符

在 Go 中, &運(yùn)算符在兩個(gè)整型操作數(shù)中執(zhí)行按位 AND操作。AND操作具有以下屬性:

Given operands a, bAND(a, b) = 1; only if a = b = 1               else = 0

AND運(yùn)算符具有選擇性的把整型數(shù)據(jù)的位清除為 0 的好的效果。 例如,我們可以使用 &運(yùn)算符去清除(設(shè)置)最后 4 個(gè)最低有效位(LSB)全部為 0 。

func main() {    var x uint8 = 0xAC    // x = 10101100    x = x & 0xF0          // x = 10100000}

所有的位運(yùn)算都支持簡寫的賦值形式。 例如,前面的例子可以重寫為如下。

func main() {    var x uint8 = 0xAC    // x = 10101100    x &= 0xF0             // x = 10100000}

另外一個(gè)巧妙的技巧是:你可以用 &操作去測試一個(gè)數(shù)字是奇數(shù)還是偶數(shù)。原因是當(dāng)一個(gè)數(shù)字的二進(jìn)制的最低位是 1 的時(shí)候,那他就是奇數(shù)。我們可以用一個(gè)數(shù)字和 1 進(jìn)行 &操作,然后在和 1 做 AND運(yùn)算,如果的到的結(jié)果是 1 ,那么這個(gè)原始的數(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 上運(yùn)行上面的例子

| 操作符

|對其整型操作數(shù)執(zhí)行按位操作?;叵胍幌?code>或操作符具備以下性質(zhì):

Given operands a, bOR(a, b) = 1; when a = 1 or b = 1              else = 0

我們可以利用按位操作符為給定的整數(shù)有選擇地設(shè)置單個(gè)位。例如,在如下示例中我們使用按位將示例數(shù)(從低位到高位(MSB))中的第 3 ,第 7 和第 8 位置為 1 。

func main() {    var a uint8 = 0    a |= 196    fmt.Printf("%b", a)}// 打印結(jié)果  11000100            ^^   ^

練習(xí)場中可運(yùn)行范例。

在使用位掩碼技術(shù)為給定的整型數(shù)字設(shè)置任意位時(shí),運(yùn)算非常有用。例如,我們可以擴(kuò)展之前的程序?yàn)樽兞?a存儲的值設(shè)置更多的位。

func main() {    var a uint8 = 0    a |= 196    a |= 3    fmt.Printf("%b", a)}// 打印結(jié)果 11000111

在練習(xí)場中可以運(yùn)行范例。

在前面的程序里,不僅要按位設(shè)置十進(jìn)制的 196,而且要設(shè)置低位上的十進(jìn)制 3。我們還可以繼續(xù)(上更多的值)設(shè)置完所有的位。

位運(yùn)算的配置用法

現(xiàn)在,回顧一下 AND(a, 1) = a 當(dāng)且僅當(dāng) a = 1。 我們可以利用這個(gè)特性去查詢其設(shè)置位的值。例如,在上述代碼中 a & 196會返回 196 是因?yàn)檫@幾位的值在 a中確實(shí)都存在。所以我們可以結(jié)合使用 ORAND運(yùn)算的方式來分別設(shè)置和讀取某位的配置值。.

接下來的源碼片段演示了這個(gè)操作。函數(shù) procstr會轉(zhuǎn)換字符串的內(nèi)容。它需要兩個(gè)參數(shù):第一個(gè), str,是將要被轉(zhuǎn)換的字符串,第二個(gè), conf,是一個(gè)使用位掩碼的方式指定多重轉(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上面運(yùn)行代碼.

上面的 procstr("HELLO PEOPLE!", LOWER|REV|CAP)方法會把字符串變成小寫,然后反轉(zhuǎn)字符串,最后把字符串里面的單詞首字母變成大寫。這個(gè)功能是通過設(shè)置 conf里的第二,三,四位的值為 14 來完成的。然后代碼使用連續(xù)的 if 語句塊來獲取這些位操作進(jìn)行對應(yīng)的字符串轉(zhuǎn)換。

^ 操作符

在 Go 中 按位 異或操作是用 ^來表示的。 異或運(yùn)算符有如下的特點(diǎn):

Given operands a, bXOR(a, b) = 1; only if a != b     else = 0

異或運(yùn)算的這個(gè)特性可以用來把二進(jìn)制位的一個(gè)值變成另外一個(gè)值。舉個(gè)例子,給到一個(gè) 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)。異或運(yùn)算的一個(gè)實(shí)際用途,例如,可以利用 異或運(yùn)算去比較兩個(gè)數(shù)字的符號是否一樣。當(dāng) (a ^ b) ≥ 0(或相反符號的 (a ^ b) < 0)為 true的時(shí)候,兩個(gè)整數(shù) a,b 具有相同的符號,如下面的程序所示:

func main() {    a, b := -12, 25    fmt.Println("a and b have same sign?", (a ^ b) >= 0)}

在 Go 的 Playground運(yùn)行代碼。

當(dāng)執(zhí)行上面這個(gè)程序的時(shí)候,將會打印出:a and b have same sign? false。在 Go Playground 上修改程序里 a ,b 的符號,以便看到不同的結(jié)果。

^ 作為取反位運(yùn)算符 (非)

不像其他語言 (c/c++,Java,Python,Javascript,等), Go 沒有專門的一元取反位運(yùn)算符。取而代之的是,XOR運(yùn)算符 ^,也可作為一元取反運(yùn)算符作用于一個(gè)數(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 a11110000     // ^a

在練習(xí)場中可以運(yùn)行范例。

&^ 操作符

&^操作符意為 與非,是 操作符的簡寫形式,它們定義如下。

Given operands a, bAND_NOT(a, b) = AND(a, NOT(b))

如果第二個(gè)操作數(shù)為 1 那么它則具有清除第一個(gè)操作數(shù)中的位的趣味特性。

AND_NOT(a, 1) = 0; clears aAND_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)}// 打?。?010101110100000

在練習(xí)場中運(yùn)行范例。

<< 和 >> 操作符

與其他 C 的衍生語言類似, Go 使用 <<>>來表示左移運(yùn)算符和右移運(yùn)算符,如下所示:

Given integer operands a and n,a << n; shifts all bits in a to the left n timesa >> n; shifts all bits in a to the right n times

例如,在下面的代碼片段中變量 a00000011)的值將會左移位運(yùn)算符分別移動三次。每次輸出結(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é)果:00000011000001100000110000011000

在 Playground 運(yùn)行代碼

注意每次移動都會將低位右側(cè)補(bǔ)零。相對應(yīng),使用右移位操作符進(jìn)行運(yùn)算時(shí),每個(gè)位均向右方移動,空出的高位補(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)}// 打?。?11110000011110000011110

在 練習(xí)場中可以運(yùn)行范例。

可以利用左移和右移運(yùn)算中,每次移動都表示一個(gè)數(shù)的 2 次冪這個(gè)特性,來作為某些乘法和除法運(yùn)算的小技巧。例如,如下代碼中,我們可以使用右移運(yùn)算將 200(存儲在變量 a 中)除以 2 。

func main() {    a := 200    fmt.Printf("%d\n", a>>1)}// 打?。?00

在 練習(xí)場 中可以運(yùn)行范例。

或是通過左移 2 位,將一個(gè)數(shù)乘以4:

func main() {    a := 12    fmt.Printf("%d\n", a<<2)}// 打?。?8

在 練習(xí)場 中可以運(yùn)行范例。

位移運(yùn)算符提供了有趣的方式處理二進(jìn)制值中特定位置的值。例如,下列的代碼中,|<<用于設(shè)置變量 a的第三個(gè) bit 位。

func main() {    var a int8 = 8    fmt.Printf("%08b\n", a)    a = a | (1<<2)    fmt.Printf("%08b\n", a)}// prints:0000100000001100

可以在 練習(xí)場 中運(yùn)行代碼示例。

或者,您可以組合位移運(yùn)算符和 &測試是否設(shè)置了第n位,如下面示例所示:

func main() {    var a int8 = 12    if a&(1<<2) != 0 {        fmt.Println("take action")    }}// 打印:take action

在 練習(xí)場中運(yùn)行代碼。

使用 &^和位移運(yùn)算符,我們可以取消設(shè)置一個(gè)值的某個(gè)位。例如,下面的示例將變量 a 的第三位置為 0 :

func main() {    var a int8 = 13     fmt.Printf("%04b\n", a)    a = a &^ (1 << 2)    fmt.Printf("%04b\n", a)}// 打印:11011001

在 練習(xí)場 中運(yùn)行代碼。

關(guān)于算術(shù)位移運(yùn)算的筆記

當(dāng)要位移的值(左操作數(shù))是有符號值時(shí),Go 自動應(yīng)用算術(shù)位移。在右移操作期間,復(fù)制(或擴(kuò)展)二進(jìn)制補(bǔ)碼符號位以填充位移的空隙。

總結(jié)

與其它現(xiàn)代運(yùn)算符一樣,Go 支持所有二進(jìn)制位操作運(yùn)算符。這篇文章僅僅提供了可以用這些操作符完成的各種黑科技示例。你可以在網(wǎng)絡(luò)上找到很多文章,特別是 Sean Eron Anderson 寫的 Bit Twiddling Hacks 。

關(guān)注 Vladim @vladimirvivien 的 Twitter。

如果你正在學(xué)習(xí) Go,閱讀 Vladimir Vivien 關(guān)于 Go 的書,名為 Learning Go Programming 。

這篇文章開始由作者 Vladimir Vivien 發(fā)布在 Medium 上,名為 Bit Hacking with Go。

推薦學(xué)習(xí):Golang教程

以上就是淺析Golang中的的位操作(按位運(yùn)算符)的詳細(xì)內(nèi)容,更多請關(guān)注php中文網(wǎng)其它相關(guān)文章!

關(guān)鍵詞: go語言 Golang