Created
August 18, 2022 20:28
-
-
Save scottcagno/8fa8bd877366e009b16c183ee9d8346d to your computer and use it in GitHub Desktop.
bitwise operations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "fmt" | |
| "strconv" | |
| ) | |
| func main() { | |
| fmt.Println() | |
| var f BitField | |
| fmt.Printf("%.32b (hex=0x%.8x)\n", f, f) | |
| f.Set(127, 0) | |
| fmt.Printf("%.32b (hex=0x%.8x)\n", f, f) | |
| f.Set(63, 1) | |
| fmt.Printf("%.32b (hex=0x%.8x)\n", f, f) | |
| f.Set(255, 2) | |
| fmt.Printf("%.32b (hex=0x%.8x)\n", f, f) | |
| f.Set(13, 3) | |
| fmt.Printf("%.32b (hex=0x%.8x)\n", f, f) | |
| fmt.Println(f.Get(0), f.Get(1),f.Get(2), f.Get(3)) | |
| // Say you want to set the second bit in x to a 1 | |
| x := StoB("11100101") | |
| // You make a number with that bit on... | |
| y := StoB("00000010") | |
| // And you do an OR operation... | |
| z := BitOR(x, y) | |
| PrintBits(x, y, z) | |
| x = StoB("00000010") | |
| fmt.Printf("%.8b << %d (produces %.8b) (left)\n", x, 1, LeftShift(x, 1)) | |
| x = StoB("00000010") | |
| fmt.Printf("%.8b << %d (produces %.8b) (left)\n", x, 2, LeftShift(x, 2)) | |
| x = StoB("00001011") | |
| fmt.Printf("%.8b >> %d (produces %.8b) (right)\n", x, 1, RightShift(x, 1)) | |
| // x = ^15 | |
| x1 := BitNOT(StoB("00001111")) | |
| PrintBits(x1) // should be 11110000, aka 240 | |
| // x = 3 & 2 | |
| x2 := BitAND(StoB("00000011"), StoB("00000010")) | |
| PrintBits(x2) // should be 00000010, aka 2 | |
| // x = 2 | 8 | |
| x3 := BitOR(StoB("00000010"), StoB("00001000")) | |
| PrintBits(x3) // should be 00001010, aka 10 | |
| // x = 5 ^ 3 | |
| x4 := BitXOR(StoB("00000101"), StoB("00000011")) | |
| PrintBits(x4) // should be 00000110, aka 6 | |
| } | |
| // BitField is a way to use a single larger datatype to store many smaller values. | |
| type BitField uint32 | |
| func (bf *BitField) Set(v uint8, pos int) { | |
| *bf |= BitField(v) << (pos << 3) | |
| } | |
| func (bf BitField) Get(pos int) uint8 { | |
| return uint8(bf >> BitField(pos<<3)) | |
| } | |
| // StoB takes a binary string representation and converts it into an uint8. | |
| func StoB(s string) uint8 { | |
| b, err := strconv.ParseUint(s, 2, 8) | |
| if err != nil { | |
| panic(err) | |
| } | |
| return uint8(b) | |
| } | |
| // BitNOT is a binary operation that takes two equal-length binary representations and | |
| // performs the logical NOT operation on each pair of the corresponding bits. NOT is a | |
| // unary operation that performs logical negation on each bit, forming the ones' complement | |
| // of the given binary value. Bits that are 0 become 1, and those that are 1 become 0. | |
| func BitNOT(x uint8) uint8 { | |
| return ^x | |
| } | |
| // BitAND is a binary operation that takes two equal-length binary representations and | |
| // performs the logical AND operation on each pair of the corresponding bits. The result | |
| // in each position is 1 if both bits are 1, otherwise the result is 0. | |
| func BitAND(x, y uint8) uint8 { | |
| return x & y | |
| } | |
| // BitOR is a binary operation that takes two equal-length binary representations | |
| // and performs the logical inclusive OR operation on each pair of corresponding bits. | |
| // The result in each position is 0 if both bits are 0, otherwise the result is 1. | |
| func BitOR(x, y uint8) uint8 { | |
| return x | y | |
| } | |
| // BitXOR is a binary operation that takes two equal-length binary representations and | |
| // performs the logical exclusive OR operation (aka XOR) on each pair of corresponding bits. | |
| // The result in each position is 1 if only one of the bits is 1, but will be 0 if both are | |
| // 0 or both are 1. IE: 1 if the two bits are different, and 0 if they are the same. | |
| func BitXOR(x, y uint8) uint8 { | |
| return x ^ y | |
| } | |
| // LeftShift is a binary operation that moves each bit in the number to the left by the | |
| // number of bits specified with `by`. When shifting left, the most-significant bit (MSB) | |
| // is lost, and a 0 bit is inserted on the other end. IE: 0010 << 1 produces 0100. It is | |
| // worth noting that a single left shift multiplies a binary number by 2. | |
| func LeftShift(x, by uint8) uint8 { | |
| return x << by | |
| } | |
| // RightShift is a binary operation that moves each bit in the number to the right by the | |
| // number of bits specified with `by`. When shifting right, the least-significant bit (LSB) | |
| // is lost, and a 0 bit is inserted on the other end. IE: 1011 >> 1 produces 0101. | |
| func RightShift(x, by uint8) uint8 { | |
| return x >> by | |
| } | |
| // PrintBits takes an uint8 and prints it out the binary value. | |
| func PrintBits(bits ...uint8) { | |
| for _, b := range bits { | |
| fmt.Printf("%.8b (decimal %.3d, hex=0x%0.2x)\n", b, b, b) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment