In low-level programming, it is common to work at the bit level. This was true in earlier days of computing and even relevant today. Most popular languages kept provisions for bit level operations, not only as a legacy, but also as a frequently used feature in their arsenal. Direct bit-level operations have their uses in cryptography, system level programming, image processing, and so forth. Here, in this Golang programming tutorial, we will go into the details of bitwise operators and how to work with them in Go.
Reading: Best Online Courses to Learn Go and Golang
Golang Bitwise Operators
Go provides the following bitwise operators:
- &: Bitwise AND
- |: Bitwise OR
- ^: Bitwise XOR
- &^: Bit clear (AND NOT)
- <<: Leftshift
- >>: Rightshift
Bitwise operators in Go deal with bit – 0 and 1 and work only on integer variables having bit patterns of equal length. The format string %b is used for bit representation. Here is a quick code example showing how to take user input and format it as a binary number in Go:
package main import “fmt” func main() { var i int fmt.Printf(“Enter number:”) fmt.Scanf(“%d”, &i) fmt.Printf(“Number %d in binary is %b”, i, i) }
Running this code in your integrated development environment (IDE) gives us the following output:
Enter number:34 Number 34 in binary is 100010
Here we have input a number into an integer variable through fmt.Scanf and used the format-string %d to print its binary form.
Use of Bit Level Operations in Go
Below are some use cases for when a developer might use bit level operations in Go:
- Since bitwise operators work on bit fields they are particularly efficient in presenting something that has “yes” and “no” or “true” or “false” properties. For example, if a programmer wants to give or revoke permission to a file (read, write, execute), instead of storing the bytes of information for the permission, we can use only three bits such as 101 = (read, execute only) or 100 (read only). This saves a lot of space.
- In a network transmission or a communication over ports/sockets that involve parity and checksums, which depend heavily on bit operation
- All encryption and compression algorithms work on a bit level and heavily use bitwise operators
- Working with images or in graphics programming, bit level operations help a lot, particularly the XOR operator has many interesting uses in graphics and image processing
- Creating logic gates, circuit development, device drivers, finite state machines, and mathematics all have numerous uses for bitwise operators
The & (AND) operator in Go
The & operator in Go performs AND operations between two integer numbers provided as an operand. The bitwise AND operation has the following characteristics:
Note that the result is 1 only when both x and y have value, otherwise it results in a 0 value. The AND operation can be used to clear – or set to 0 – certain bit positions in a number. This idea can be used in numerous creative ways. For example, if a programmer wants to find a number ODD or EVEN, they may use the & operator in the following way:
x := 125 if (x & 0x1) > 0 { fmt.Println(“ODD”) } else { fmt.Println(“EVEN”) }
This trick works because every ODD number has 1 as the least significant bit (LSB) and the AND operation will clear all the bits except the LSB. As such, the result of the if condition will be true if the value ANDed with 0x1 is greater than 0, which means the number is ODD and false otherwise.
The | (OR) operator in Go
The | operator in Go performs OR operations between two integer numbers provided as an operand. The bitwise OR operation has the following characteristics:
Note that, in this case, the result is 1 when at least any one input is 1, and 0 otherwise. This property can be used to set certain bits, unlike AND, which can be used to clear certain bits. Suppose we want to set the LSB of a decimal number 10 (in binary 1010). After setting the LSB, the result should be 11 (in binary 1011). Here is the code to perform this task:
var set_bit uint32 = 0x1 var value uint32 = 0xA fmt.Printf(“%b”, value|set_bit)
So, if & (AND) operation can be used for clearing bits, | (OR) can be used for setting bits.
Reading: Understanding Mathematical Operators in Go
The ^ (XOR) operator in Go
The ^ operator in Go performs OR operations between two integer numbers provided as an operand. The bitwise OR operation has the following characteristics:
In this case, the output is 1 only when both the input values are different. If both input values are the same, it would result in 0 when XORed. The XOR operator has many interesting uses in computing. It is particularly used to toggle values, such as changing value 0 to 1 and 1 to 0 in a sequence of bits. A common trick with XOR is to swap values of two variables without using a third/another variable. Here is a code example showing how to execute this idea in Go:
x := 5 y := 6 fmt.Printf(“nBefore swap: x=%d,y=%d”, x, y) x = x ^ y y = x ^ y x = x ^ y fmt.Printf(” nAfter swap x=%d,y=%d”, x, y)
The above Golang code exchanges (or swaps) the value stored in x to y and y to x using the XOR operator.
The &^ (AND NOT) operator in Go
The &^ (AND NOT) operator in Go is a bit interesting because the actual operator is ^ and the &^ is just used to separate it from the XOR operator. The reason is that, unlike C/C++ which have a dedicated unary NOT operator represented by the exclamation sign (!), Go does not have a bitwise NOT operator (not to be confused with the ! Logical not operator). Therefore, to negate anything, programmers can use the same ^ (XOR) operator acting as a bitwise NOT. The bitwise NOT actually produces one’s complement of a number. So, a given bit x and ^x would be a complement of each other. Here is a simple code example showing how to use the &^ (AND NOT) operator in Go:
var x uint8 = 129 fmt.Printf(“nx=%b,^x=%b”, x, ^x)
the< (left-shift) and >> (right-shift) Operators in Go
the< left-shift and >> right-shift operators in Go shift the number of bit positions to the left by inserting 0 as the LSB, and right by inserting 0 to the MSB, respectively. For example, a given integer x can be shifted left by n bits or shifted right by n bits as follows:
x< n, shifts x to the left by n bits x >> n, shift x to the right by n bits
Among many of its interesting uses in programming, if programmers left shift a number by 1 bit, it gives a result of the value multiplied by 2. Similarly, if we right shift a number by 1 bit, we get a quotient of the value divided by 2. Here is a quick code example illustrating the idea:
var x uint8 = 10 fmt.Printf(“n%dx 2 = %d”, x, x<1) fmt.Printf("n%d / 2 = %d", x, x>>1)
Final Thoughts on Bitwise Operators in Go
Sometimes developers get confused when we see similar operations are performed with bitwise and logical operators. To allay such a confusion, bitwise operators always produce numeric bit values, while logical operators produce only two values - either true or false, which are non-numeric. This simple distinction makes it all clear. Bitwise operations have numerous interesting and tricky uses. Sometimes a lengthy logic can be made short and quick using bitwise operators. Working with bitwise operators in Go and Golang not only has a low-level feel, but is also quite fun to work with.
read more Go and Golang programming tutorials and software development tips.