We will go over three tricks—checking whether the signs of integers are different, checking whether a number is a power of two, and calculating the modulus of a number that is a power of two. We will show an operators-only notation and one using the corresponding NumPy functions:
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. ^
corresponds to the bitwise_xor
function. <
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.
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 two would 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 the AND operator a power of two, and the integer that is one less than that, then we should get 0
. The NumPy counterpart of &
is bitwise_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]
11
, 111
, or 1111
. This basically gives us a mask. Bitwise-ANDing with such a number gives you the remainder with a power of two. 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]
We covered three bit-twiddling hacks—checking whether the signs of integers are different, checking whether a number is a power of two, and calculating the modulus of a number that is a power of two. We saw the NumPy counterparts of the operators ^
, &
, <<
, and <
(see bittwidling.py
):
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)