Time for action – twiddling bits

We will now cover three tricks—checking whether the signs of integers are different, checking whether a number is a power of 2, and calculating the modulus of a number that is a power of 2. We will show an operators-only notation and one using the corresponding NumPy functions:

  1. The first trick depends on the XOR or ^ operator. The XOR operator is also called the inequality operator; so, if the sign bit of the two operands is different, the XOR operation will lead to a negative number (see https://www.khanacademy.org/computing/computer-science/cryptography/ciphers/a/xor-bitwise-operation).

    The following truth table illustrates the XOR operator:

    Input 1

    Input 2

    XOR

    True

    True

    False

    False

    True

    True

    True

    False

    True

    False

    False

    False

    The ^ operator corresponds to the bitwise_xor() function, and the < operator corresponds to the less() function:

    x = np.arange(-9, 9)
    y = -x
    print("Sign different?", (x ^ y) < 0)
    print("Sign different?", np.less(np.bitwise_xor(x, y), 0))

    The result is shown as follows:

    Sign different? [ True  True  True  True  True  True  True  True  True False  True  True
      True  True  True  True  True  True]
    Sign different? [ True  True  True  True  True  True  True  True  True False  True  True
      True  True  True  True  True  True]
    

    As expected, all the signs differ, except for zero.

  2. A power of 2 is represented by a 1, followed by a series of trailing zeroes in binary notation. For instance, 10, 100, or 1000. A number one less than a power of 2 will be represented by a row of ones in binary. For instance, 11, 111, or 1111 (or 3, 7, and 15 in the decimal system). Now, if we bitwise AND a power of 2, and the integer that is one less than that, then we should get 0.

    The truth table for the AND operator looks like the following:

    Input 1

    Input 2

    AND

    True

    True

    True

    False

    True

    False

    True

    False

    False

    False

    False

    False

    The NumPy counterpart of & is bitwise_and(), and the counterpart of == is the equal() universal function:

    print("Power of 2?
    ", x, "
    ", (x & (x - 1)) == 0)
    print("Power of 2?
    ", x, "
    ", np.equal(np.bitwise_and(x,  (x - 1)), 0))

    The result is shown as follows:

    Power of 2?
    [-9 -8 -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  8] 
    [False False False False False False False False False  True  True  True
     False  True False False False  True]
    Power of 2?
    [-9 -8 -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  8] 
    [False False False False False False False False False  True  True  True
     False  True False False False  True]
    
  3. The trick of computing the modulus of 4 actually works when taking the modulus of integers that are a power of 2 such as 4, 8, 16, and so on. A bitwise left shift leads to doubling of values (see https://wiki.python.org/moin/BitwiseOperators). We saw in the previous step that subtracting one from a power of 2 leads to a number in binary notation that has a row of ones such as 11, 111, or 1111. This basically gives us a mask. Bitwise-ANDing with such a number gives you the remainder with a power of 2. The NumPy equivalent of << is the left_shift() universal function:
    print("Modulus 4
    ", x, "
    ", x & ((1 << 2) - 1))
    print("Modulus 4
    ", x, "
    ", np.bitwise_and(x, np.left_shift(1, 2) - 1))

    The result is shown as follows:

    Modulus 4
    [-9 -8 -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  8] 
    [3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0]
    Modulus 4
    [-9 -8 -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  8] 
    [3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0]
    

What just happened?

We covered three bit twiddling hacks—checking whether the signs of integers are different, checking whether a number is a power of 2, and calculating the modulus of a number that is a power of 2. We saw the NumPy counterparts of the operators ^, &, <<, and < (see bittwidling.py):

from __future__ import print_function
import numpy as np

x = np.arange(-9, 9)
y = -x
print("Sign different?", (x ^ y) < 0)
print("Sign different?", np.less(np.bitwise_xor(x, y), 0))
print("Power of 2?
", x, "
", (x & (x - 1)) == 0)
print("Power of 2?
", x, "
", np.equal(np.bitwise_and(x,  (x - 1)), 0))
print("Modulus 4
", x, "
", x & ((1 << 2) - 1))
print("Modulus 4
", x, "
", np.bitwise_and(x, np.left_shift(1, 2) - 1))
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset