0% found this document useful (0 votes)
68 views

Programare Bit Operations

1. Bitwise operators perform operations on bits of numbers. The six bitwise operators in C/C++ are & (AND), | (OR), ^ (XOR), << (left shift), >> (right shift), and ~ (bitwise NOT). 2. The document provides examples of using each operator, such as using XOR to find the odd occurring number in an array. It also discusses interesting facts like how left/right shift behave for negative numbers. 3. The document recommends problems that can be solved using bitwise operators, such as finding the missing number, swapping without a temp variable, and more. It cautions against using bitwise operators instead of logical ones.

Uploaded by

Vasilica
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
68 views

Programare Bit Operations

1. Bitwise operators perform operations on bits of numbers. The six bitwise operators in C/C++ are & (AND), | (OR), ^ (XOR), << (left shift), >> (right shift), and ~ (bitwise NOT). 2. The document provides examples of using each operator, such as using XOR to find the odd occurring number in an array. It also discusses interesting facts like how left/right shift behave for negative numbers. 3. The document recommends problems that can be solved using bitwise operators, such as finding the missing number, swapping without a temp variable, and more. It cautions against using bitwise operators instead of logical ones.

Uploaded by

Vasilica
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 18

Bitwise Operators in C/C++

In C, the following 6 operators are bitwise operators (work at bit-level)

1.The & (bitwise AND) in C or C++ takes two numbers as operands and


does AND on every bit of two numbers. The result of AND is 1 only if both
bits are 1.
2.The | (bitwise OR) in C or C++ takes two numbers as operands and
does OR on every bit of two numbers. The result of OR is 1 if any of the
two bits is 1.
3.The ^ (bitwise XOR) in C or C++ takes two numbers as operands and
does XOR on every bit of two numbers. The result of XOR is 1 if the two
bits are different.
4.The << (left shift) in C or C++ takes two numbers, left shifts the bits of
the first operand, the second operand decides the number of places to
shift.
5.The >> (right shift) in C or C++ takes two numbers, right shifts the bits
of the first operand, the second operand decides the number of places to
shift.
6.The ~ (bitwise NOT) in C or C++ takes one number and inverts all bits
of it
Example:
// C Program to demonstrate use of bitwise operators
#include <stdio.h>
int main()
{
    // a = 5(00000101), b = 9(00001001)
    unsigned char a = 5, b = 9;
  
    // The result is 00000001
    printf("a = %d, b = %d\n", a, b);
    printf("a&b = %d\n", a & b);
  
    // The result is 00001101
    printf("a|b = %d\n", a | b);
  
    // The result is 00001100
    printf("a^b = %d\n", a ^ b);
  
    // The result is 11111010
    printf("~a = %d\n", a = ~a);
  
    // The result is 00010010
    printf("b<<1 = %d\n", b << 1);
  
    // The result is 00000100
    printf("b>>1 = %d\n", b >> 1);
  
    return 0;
}

Output:
a = 5, b = 9
a&b = 1
a|b = 13
a^b = 12
~a = 250
b<<1 = 18
b>>1 = 4
Interesting facts about bitwise operators
The left shift and right shift operators should not be used for negative
numbers. If any of the operands is a negative number, it results in undefined
behaviour. For example results of both -1 << 1 and 1 << -1 is undefined.
Also, if the number is shifted more than the size of integer, the behaviour is
undefined. For example, 1 << 33 is undefined if integers are stored using 32
bits. See this for more details.
1.The bitwise XOR operator is the most useful operator from technical
interview perspective. It is used in many problems. A simple example
could be “Given a set of numbers where all elements occur even number
of times except one number, find the odd occurring number” This problem
can be efficiently solved by just doing XOR of all numbers.
#include <stdio.h>
  
// Function to return the only odd
// occurring element
int findOdd(int arr[], int n)
{
    int res = 0, i;
    for (i = 0; i < n; i++)
        res ^= arr[i];
    return res;
}
  
// Driver Method
int main(void)
{
    int arr[] = { 12, 12, 14, 90, 14, 14, 14 };
    int n = sizeof(arr) / sizeof(arr[0]);
    printf("The odd occurring element is %d ",
           findOdd(arr, n));
    return 0;
}

Output:
The odd occurring element is 90

The following are many other interesting problems using XOR operator.

1.Find the Missing Number


2.swap two numbers without using a temporary variable
3.A Memory Efficient Doubly Linked List
4.Find the two non-repeating elements.
5.Find the two numbers with odd occurences in an unsorted-
array.
6.Add two numbers without using arithmetic operators.
7.Swap bits in a given number/.
8.Count number of bits to be flipped to convert a to b .
9.Find the element that appears once.
10.Detect if two integers have opposite signs.
.

2.The bitwise operators should not be used in place of logical


operators. The result of logical operators (&&, || and !) is either 0 or 1, but
bitwise operators return an integer value. Also, the logical operators
consider any non-zero operand as 1. For example, consider the following
program, the results of & and && are different for same operands.
#include <stdio.h>
  
int main()
{
    int x = 2, y = 5;
    (x & y) ? printf("True ") : printf("False ");
    (x && y) ? printf("True ") : printf("False ");
    return 0;
}

Output:
False True

3.The left-shift and right-shift operators are equivalent to multiplication


and division by 2 respectively. As mentioned in point 1, it works only if
numbers are positive.
#include <stdio.h>
  
int main()
{
    int x = 19;
    printf("x << 1 = %d\n", x << 1);
    printf("x >> 1 = %d\n", x >> 1);
    return 0;
}

Output:
x << 1 = 38

x >> 1 = 9

4.The & operator can be used to quickly check if a number is odd or


even. The value of expression (x & 1) would be non-zero only if x is odd,
otherwise the value would be zero.
#include <stdio.h>
  
int main()
{
    int x = 19;
    (x & 1) ? printf("Odd") : printf("Even");
    return 0;
}

Output:
Odd

5.The ~ operator should be used carefully. The result of ~ operator on a


small number can be a big number if the result is stored in an unsigned
variable. And the result may be a negative number if the result is stored in
a signed variable (assuming that the negative numbers are stored in 2’s
complement form where the leftmost bit is the sign bit)
// Note that the output of the following
// program is compiler dependent
#include <stdio.h>
  
int main()
{
    unsigned int x = 1;
    printf("Signed Result %d \n", ~x);
    printf("Unsigned Result %ud \n", ~x);
    return 0;
}

Output:
Signed Result -2

Unsigned Result 4294967294d

Important Links:
1.Bits manipulation (Important tactics)
2.Bitwise Hacks for Competitive Programming
3.Bit Tricks for Competitive Programming

Bitwise Hacks for Competitive


Programming
It is recommended to refer Interesting facts about Bitwise
Operators as a prerequisite.
1. How to set a bit in the number ‘num’ :
If we want to set a bit at nth position in number ‘num’ ,it can be done
using ‘OR’ operator( | ).
•First we left shift ‘1’ to n position via (1<<n)
•Then, use ‘OR’ operator to set bit at that position.’OR’ operator is used
because it will set the bit even if the bit is unset previously in binary
representation of number ‘num’.
#include<iostream>
using namespace std;
// num is the number and pos is the position 
// at which we want to set the bit.
void set(int & num,int pos)
{
     // First step is shift '1', second
     // step is bitwise OR
     num |= (1 << pos);
}
int main()
{
     int num = 4, pos = 1;
     set(num, pos);
     cout << (int)(num) << endl;
     return 0;
}

Output:
6
We have passed the parameter by ‘call by reference’ to make permanent
changes in the number.
2. How to unset/clear a bit at n’th position in the number ‘num’ :
Suppose we want to unset a bit at nth position in number ‘num’ then we
have to do this with the help of ‘AND’ (&) operator.
•First we left shift ‘1’ to n position via (1<<n) than we use bitwise NOT
operator ‘~’ to unset this shifted ‘1’.
•Now after clearing this left shifted ‘1’ i.e making it to ‘0’ we will ‘AND'(&)
with the number ‘num’ that will unset bit at nth position position.
#include <iostream>
using namespace std;
// First step is to get a number that  has all 1's except the given
position.
void unset(int &num,int pos)
{
    //Second step is to bitwise and this  number with given number
    num &= (~(1 << pos));
}
int main()
{
    int num = 7;
    int  pos = 1;
    unset(num, pos);
    cout << num << endl;
    return 0;
}

Output:
5
3.  Toggling a bit at nth position :
Toggling means to turn bit ‘on'(1) if it was ‘off'(0) and to turn ‘off'(0) if it was
‘on'(1) previously.We will be using ‘XOR’ operator here which is this ‘^’. The
reason behind ‘XOR’ operator is because of its properties.
•Properties of ‘XOR’ operator.
•1^1 = 0
•0^0 = 0
•1^0 = 1
•0^1 = 1
•If two bits are different then ‘XOR’ operator returns a set bit(1) else it
returns an unset bit(0).
#include <iostream>
using namespace std;
// First step is to shift 1,Second step is to XOR with given number
void toggle(int &num,int pos)
{
    num ^= (1 << pos);
}
int main()
{
    int num = 4;
    int pos = 1;
    toggle(num, pos);
    cout << num << endl;
    return 0;
}

Output:
6
4. Checking if bit at nth position is set or unset:
It is quite easily doable using ‘AND’ operator.
Left shift ‘1’ to given position and then ‘AND'(‘&’).
#include <iostream>
using namespace std;
  
bool at_position(int num,int pos)
{
    bool bit = num & (1<<pos);
    return bit;
}
  
int main()
{
    int num = 5;
    int pos = 0;
    bool bit = at_position(num, pos);
    cout << bit << endl;
    return 0;
}

Output:
1
Observe that we have first left shifted ‘1’ and then used ‘AND’ operator to
get bit at that position. So if there is ‘1’ at position ‘pos’ in ‘num’, then after
‘AND’ our variable ‘bit’ will store ‘1’ else if there is ‘0’ at position ‘pos’ in the
number ‘num’ than after ‘AND’ our variable bit will store ‘0’.
Some more quick hacks:
•Inverting every bit of a number/1’s complement:
If we want to invert every bit of a number i.e change bit ‘0’ to ‘1’ and bit
‘1’ to ‘0’.We can do this with the help of ‘~’ operator. For example : if
number is num=00101100 (binary representation) so ‘~num’ will be
‘11010011’.

This is also the ‘1s complement of number’.


#include <iostream>
using namespace std;
int main()
{
    int num = 4;
  
    // Inverting every bit of number num
    cout << (~num);
    return 0;
}

Output:
-5
• Two’s complement of the number: 2’s complement of a number is 1’s
complement + 1.
So formally we can have 2’s complement by finding 1s complement and
adding 1 to the result i.e (~num+1) or what else we can do is using ‘-‘
operator.
#include <iostream>
using namespace std;
int main()
{
    int num = 4;
    int twos_complement = -num;
    cout << "This is two's complement " << twos_complement << endl;
    cout << "This is also two's complement " << (~num+1) << endl;
    return 0;
}

Output:
This is two's complement -4
This is also two's complement -4
•Stripping off the lowest set bit :
In many situations we want to strip off the lowest set bit for example in
Binary Indexed tree data structure, counting number of set bit in a number.
We do something like this:
X = X & (X-1)
But how does it even work ?
Let us see this by taking an example, let X = 1100.
(X-1)  inverts all the bits till it encounter lowest set ‘1’ and it also invert that
lowest set ‘1’.
X-1 becomes 1011. After ‘ANDing’ X with X-1 we get lowest set bit stripped.
#include <iostream>
using namespace std;
void strip_last_set_bit(int &num)
{
    num = num & (num-1);
}
int main()
{
    int num = 7;
    strip_last_set_bit(num);
    cout << num << endl;
    return 0;
}

Output:
6
•Getting lowest set bit of a number:
This is done by using expression ‘X &(-X)’Let us see this by taking an
example:Let X = 00101100. So ~X(1’s complement) will be ‘11010011’ and
2’s complement will be (~X+1 or -X) i.e  ‘11010100’.So if we ‘AND’ original
number ‘X’ with its two’s complement which is ‘-X’, we get lowest set bit.
00101100
& 11010100
-----------
00000100
#include <iostream>
using namespace std;
int lowest_set_bit(int num)
{
    int ret = num & (-num);
    return ret;
}
int main()
{
    int num = 10;
Output:
2
Bit Tricks for Competitive Programming
Refer BitWise Operators Articles for more articles on Bit Hacks.

Bit Tricks for Competitive Programming


In competitive programming or in general some problems seems difficult but
can be solved very easily with little bit magic. We have discussed some tricks
in below previous post.
Bitwise Hacks for Competitive Programming
We have considered below facts in this article –
•0 based indexing of bits from left to right.
•Setting i-th bit means, turning i-th bit to 1
•Clearing i-th bit means, turning i-th bit to 0
1) Clear all bits from LSB to ith bit
mask = ~((1 << i+1 ) - 1);
x &= mask;
Logic: To clear all bits from LSB to i-th bit, we have to AND x with mask
having LSB to i-th bit 0. To obtain such mask, first left shift 1 i times. Now if
we minus 1 from that, all the bits from 0 to i-1 become 1 and remaining bits
become 0. Now we can simply take complement of mask to get all first i bits
to 0 and remaining to 1.
Example-
x = 29 (00011101) and we want to clear LSB to 3rd bit, total 4 bits
mask -> 1 << 4 -> 16(00010000)
mask -> 16 – 1 -> 15(00001111)
mask -> ~mask -> 11110000
x & mask -> 16 (00010000)
2) Clearing all bits from MSB to i-th bit
mask = (1 << i) - 1;
x &= mask;
Logic: To clear all bits from MSB to i-th bit, we have to AND x with mask
having MSB to i-th bit 0. To obtain such mask, first left shift 1 i times. Now if
we minus 1 from that, all the bits from 0 to i-1 become 1 and remaining bits
become 0.
Example-
x = 215 (11010111) and we want to clear MSB to 4th bit, total 4 bits
mask -> 1 << 4 -> 16(00010000)
mask -> 16 – 1 -> 15(00001111)
x & mask -> 7(00000111)
3) Divide by 2
x >>= 1;
Logic: When we do arithmetic right shift, every bit is shifted to right and
blank position is substituted with sign bit of number, 0 in case of positive and
1 in case of negative number. Since every bit is a power of 2, with each shift
we are reducing the value of each bit by factor of 2 which is equivalent to
division of x by 2.
Example-
x = 18(00010010)
x >> 1 = 9 (00001001)
4) Multiplying by 2
x <<= 1;
Logic: When we do arithmetic left shift, every bit is shifted to left and blank
position is substituted with 0 . Since every bit is a power of 2, with each shift
we are increasing the value of each bit by a factor of 2 which is equivalent to
multiplication of x by 2.
Example-
x = 18(00010010)
x << 1 = 36 (00100100)
5) Upper case English alphabet to lower case
ch |= ' ';
Logic: The bit representation of upper case and lower case English alphabets
are –
A -> 01000001 a -> 01100001
B -> 01000010 b -> 01100010
C -> 01000011 c -> 01100011
. .
. .
Z -> 01011010 z -> 01111010
As we can see if we set 5th bit of upper case characters, it will be converted
into lower case character. We have to prepare a mask having 5th bit 1 and
other 0 (00100000). This mask is bit representation of space character (‘ ‘).
The character ‘ch’ then ORed with mask.
Example-
ch = ‘A’ (01000001)
mask = ‘ ‘ (00100000)
ch | mask = ‘a’ (01100001)
Please refer Case conversion (Lower to Upper and Vice Versa) for
details.
6) Lower case English alphabet to upper case
ch &= '_’ ;
Logic: The bit representation of upper case and lower case English alphabets
are –
A -> 01000001 a -> 01100001
B -> 01000010 b -> 01100010
C -> 01000011 c -> 01100011
. .
. .
Z -> 01011010 z -> 01111010
As we can see if we clear 5th bit of lower case characters, it will be converted
into upper case character. We have to prepare a mask having 5th bit 0 and
other 1 (10111111). This mask is bit representation of underscore character
(‘_‘). The character ‘ch’ then AND with mask.
Example-
ch = ‘a’ (01100001)
mask = ‘_ ‘ (11011111)
ch & mask = ‘A’ (01000001)
Please refer Case conversion (Lower to Upper and Vice Versa) for
details.
7) Count set bits in integer
int countSetBits(int x)
{
    int count = 0;
    while (x)
    {
        x &= (x-1);
        count++;
    }
    return count;
}

Logic: This is Brian Kernighan’s algorithm.


8) Find log base 2 of 32 bit integer
int log2(int x)
{
    int res = 0;
    while (x >>= 1)
        res++;
    return res;
}
Logic: We right shift x repeatedly until it becomes 0, meanwhile we keep
count on the shift operation. This count value is the log2(x).
9) Checking if given 32 bit integer is power of 2
int isPowerof2(int x)
{
    return (x && !(x & x-1));
}

Logic: All the power of 2 have only single bit set e.g. 16 (00010000). If we
minus 1 from this, all the bits from LSB to set bit get toggled, i.e., 16-1 = 15
(00001111). Now if we AND x with (x-1) and the result is 0 then we can say
that x is power of 2 otherwise not. We have to take extra care when x = 0.
Example
x = 16(000100000)
x – 1 = 15(00001111)
x & (x-1) = 0
so 16 is power of 2

Bits manipulation (Important


tactics)
Prerequisites : Bitwise operators in C, Bitwise Hacks for Competitive
Programming, Bit Tricks for Competitive Programming
1.Compute XOR from 1 to n (direct method) :
// Direct XOR of all numbers from 1 to n
int computeXOR(int n)
{
    if (n % 4 == 0)
        return n;
    if (n % 4 == 1)
        return 1;
    if (n % 4 == 2)
        return n + 1;
    else
        return 0;
}

Input: 6
Output: 7

Refer Compute XOR from 1 to n for details.


2.We can quickly calculate the total number of combinations with numbers
smaller than or equal to with a number whose sum and XOR are equal.
Instead of using looping (Brute force method), we can directly find it by a
mathematical trick i.e.
// Refer Equal Sum and XOR for details.
Answer = pow(2, count of zero bits)

3.How to know if a number is a power of 2?


//  Function to check if x is power of 2
bool isPowerOfTwo(int x)
{
     // First x in the below expression is
     // for  the case when x is 0 
     return x && (!(x & (x - 1)));
}

Refer check if a number is power of two for details.


4.Find XOR of all subsets of a set. We can do it in O(1) time. The answer is
always 0 if given set has more than one elements. For set with single
element, the answer is value of single element. Refer XOR of the XOR’s
of all subsets for details.
5.We can quickly find number of leading, trailing zeroes and number of 1’s
in a binary code of an integer in C++ using GCC. It can be done by using
inbuilt function i.e.
Number of leading zeroes: builtin_clz(x)

Number of trailing zeroes : builtin_ctz(x)

Number of 1-bits: __builtin_popcount(x)

Refer GCC inbuilt functions for details.


6.Convert binary code directly into an integer in C++.
// Conversion into Binary code//
#include <iostream>
using namespace std;
  
int main()
{
    auto number = 0b011;
    cout << number;
    return 0;
}

Output: 3

7.The Quickest way to swap two numbers:


a ^= b;

b ^= a;

a ^= b;

Refer swap two numbers for details.


8.Simple approach to flip the bits of a number: It can be done by a simple
way, just simply subtract the number from the value obtained when all the
bits are equal to 1 .
For example:
Number : Given Number

Value : A number with all bits set in given number.

Flipped number = Value – Number.

Example :

Number = 23,

Binary form: 10111;

After flipping digits number will be: 01000;

Value: 11111 = 31;


9.We can find the most significant set bit in O(1) time for a fixed size
integer. For example below cocde is for 32 bit integer.
int setBitNumber(int n)
{      
    // Below steps set bits after
    // MSB (including MSB)
  
    // Suppose n is 273 (binary 
    // is 100010001). It does following
    // 100010001 | 010001000 = 110011001
    n |= n>>1;
  
    // This makes sure 4 bits
    // (From MSB and including MSB)
    // are set. It does following
    // 110011001 | 001100110 = 111111111
    n |= n>>2;   
  
    n |= n>>4;  
    n |= n>>8;
    n |= n>>16;
      
    // Increment n by 1 so that
    // there is only one set bit
    // which is just before original
    // MSB. n now becomes 1000000000
    n = n + 1;
  
    // Return original MSB after shifting.
    // n now becomes 100000000
    return (n >> 1);
Refer Find most significant set bit of a number for details.
10.We can quickly check if bits in a number are in alternate pattern (like
101010). We compute n ^ (n >> 1). If n has an alternate pattern, then n ^
(n >> 1) operation will produce a number having set bits only. ‘^’ is a
bitwise XOR operation. Refer check if a number has bits in alternate
pattern for details.

You might also like