Friday 14 August 2015

Low-level bit hacks that every programmer must know

Bit level hacks enable you to manipulate integers in intelligent way. Instead of performing some operations by looping over individual bits, you can get the result by performing simple bit level operations.

Java provides rice bit wise operators, to perform inversion, left shift, right shift, bitwise and, o and Ex-OR operations.

Operator
Description
~
Inverts a bit pattern
<< 
Perform Left shift
>> 
Perform Right Shift
>>> 
Perform unsigned right shift
&
Bit wise AND
|
Bit wise OR
^
Bit wise Exclusive OR

For more information on Bitwise operators go through following link.

Hack 1: Swap two numbers
Usually, you swap two numbers using a temporary variable like below.

temp = a
a = b
b = c

We can achieve the same functionality using X-OR (^) operator.

a = a ^ b;
b = a ^ b;
a = a ^ b;

Hack 2: Check whether a number is power of 2
If n is a power of 2, then n&(n-1) is equal to 0.

Number
Binary
Number-1
Binary
2
00000010
1
00000001
4
00000100
3
00000011
8
00001000
7
00000111
16
00010000
15
00001111
32
00100000
31
00011111
Observe above table, you can understand the logic easily.

Hack 3: Count all set bits in an integer
Do bit wise and operation of num with 1. If result is 1, increment the counter. Right shift number by 1. Repeat this procedure until num > 0.

int count = 0;
while (num > 0) {
         count = count + (num & 1);
         num = num >> 1;
}

Hack 4: Count all unset bits in an integer
Logic is just opposite to previous logic.

while (num > 0) {
         if ((num & 1) == 0)
                  count = count + 1;
         num = num >> 1;
         System.out.println(num);
}

Hack 5: Check whether nth bit is set or not
Shift 1 to n times left, and bitwise and with n, if result is 1, then nth bit set, else not.

public static boolean isNthBitSet(int num, int n){
         int temp = 1 << n;
         return ((num & temp) != 0);
}

Hack 6: Check number is even or odd without division
If number is even, then last bit is 0, else 1.

public static boolean isEven(int num) {
         return ((num & 1) == 0);
}

Hack 7: Set nth bit of a number
Left Shift 1, n times and perform bitwise or operation.

public static int setNthBit(int num, int nthBit){
  num = (num | (1 << nthBit));
  return num;
 }

Hack 8: Toggle nth bit
If nth bit of a number is 0, then make it as 1, else 0.

public static int toggleNthBit(int num, int n) {
  num = num ^ (1 << n);
  return num;
 }

Hack 9: Isolate right most set bit
‘x = x & (-x)’ isolate right most set bit.

100            000001100100
-100            111110011100
-------------------------------
100 & -100 000000000100
-------------------------------


Following is the complete java program for above hacks.
public class BitUtil {

 public static boolean isPowerOfTwo(int n) {
  return ((n & (n - 1)) == 0);
 }

 public static int getNumSetBits(int num) {
  int count = 0;

  while (num > 0) {
   count = count + (num & 1);
   num = num >> 1;
  }
  return count;
 }

 public static int getNumUnsetBits(int num) {
  int count = 0;

  if (num == 0)
   return 1;

  while (num > 0) {
   if ((num & 1) == 0)
    count = count + 1;
   num = num >> 1;
  }

  return count;
 }

 public static boolean isNthBitSet(int num, int n) {
  int temp = 1 << n;
  return ((num & temp) != 0);
 }

 public static boolean isEven(int num) {
  return ((num & 1) == 0);
 }

 public static int setNthBit(int num, int nthBit) {
  num = (num | (1 << nthBit));
  return num;
 }

 public static int toggleNthBit(int num, int n) {
  num = num ^ (1 << n);
  return num;
 }

 public static int isolateRightMostNthBit(int num) {
  num = num & (-num);
  return num;
 }

}


Following is the junit test case for above program.
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

public class BitUtilTest {

 @Test
 public void testIsPowerOfTwo() {
  assertTrue(BitUtil.isPowerOfTwo(2));
  assertTrue(BitUtil.isPowerOfTwo(4));
  assertTrue(BitUtil.isPowerOfTwo(8));
  assertTrue(BitUtil.isPowerOfTwo(16));
  assertTrue(BitUtil.isPowerOfTwo(32));
  assertTrue(BitUtil.isPowerOfTwo(64));
  assertTrue(BitUtil.isPowerOfTwo(1));

  assertFalse(BitUtil.isPowerOfTwo(3));
  assertFalse(BitUtil.isPowerOfTwo(5));
  assertFalse(BitUtil.isPowerOfTwo(6));
  assertFalse(BitUtil.isPowerOfTwo(7));
 }

 @Test
 public void testGetNumSetBits() {
  assertEquals(BitUtil.getNumSetBits(0), 0);
  assertEquals(BitUtil.getNumSetBits(1), 1);
  assertEquals(BitUtil.getNumSetBits(2), 1);
  assertEquals(BitUtil.getNumSetBits(3), 2);
  assertEquals(BitUtil.getNumSetBits(4), 1);
  assertEquals(BitUtil.getNumSetBits(5), 2);
  assertEquals(BitUtil.getNumSetBits(6), 2);
  assertEquals(BitUtil.getNumSetBits(7), 3);
  assertEquals(BitUtil.getNumSetBits(8), 1);
 }

 @Test
 public void testGetNumUnsetBits() {
  assertEquals(BitUtil.getNumUnsetBits(0), 1);
  assertEquals(BitUtil.getNumUnsetBits(1), 0);
  assertEquals(BitUtil.getNumUnsetBits(2), 1);
  assertEquals(BitUtil.getNumUnsetBits(3), 0);
  assertEquals(BitUtil.getNumUnsetBits(4), 2);
  assertEquals(BitUtil.getNumUnsetBits(5), 1);
  assertEquals(BitUtil.getNumUnsetBits(6), 1);
  assertEquals(BitUtil.getNumUnsetBits(7), 0);
  assertEquals(BitUtil.getNumUnsetBits(8), 3);
 }

 @Test
 public void testIsNthBitSet() {
  System.out.println(165 & 4);
  assertTrue(BitUtil.isNthBitSet(165, 0));
  assertTrue(BitUtil.isNthBitSet(165, 2));
  assertTrue(BitUtil.isNthBitSet(165, 5));
  assertTrue(BitUtil.isNthBitSet(165, 7));

  assertFalse(BitUtil.isNthBitSet(165, 1));
  assertFalse(BitUtil.isNthBitSet(165, 3));
  assertFalse(BitUtil.isNthBitSet(165, 4));
  assertFalse(BitUtil.isNthBitSet(165, 6));
  assertFalse(BitUtil.isNthBitSet(165, 8));
  assertFalse(BitUtil.isNthBitSet(165, 9));
  assertFalse(BitUtil.isNthBitSet(165, 10));
 }

 @Test
 public void testIsEven() {
  assertTrue(BitUtil.isEven(0));
  assertTrue(BitUtil.isEven(2));
  assertTrue(BitUtil.isEven(4));

  assertFalse(BitUtil.isEven(1));
  assertFalse(BitUtil.isEven(3));
  assertFalse(BitUtil.isEven(5));

 }

 @Test
 public void testSetNthBit() {
  assertEquals(BitUtil.setNthBit(42, 0), 43);
  assertEquals(BitUtil.setNthBit(43, 2), 47);
  assertEquals(BitUtil.setNthBit(47, 4), 63);
 }

 @Test
 public void testToggleNthBit() {
  assertEquals(BitUtil.toggleNthBit(171, 0), 170);
  assertEquals(BitUtil.toggleNthBit(170, 6), 234);
  assertEquals(BitUtil.toggleNthBit(234, 3), 226);
  assertEquals(BitUtil.toggleNthBit(226, 7), 98);
 }

 @Test
 public void testIsolateNthBit() {
  assertEquals(BitUtil.isolateRightMostNthBit(100), 4);
  assertEquals(BitUtil.isolateRightMostNthBit(123), 1);
  assertEquals(BitUtil.isolateRightMostNthBit(204), 4);
  assertEquals(BitUtil.isolateRightMostNthBit(256), 256);
 }
}


If you are interested in learning more bit level hacks, go through following link.



No comments:

Post a Comment