parallel-bc.pl

Code Index:

http://gurmeetsingh.wordpress.com/2008/08/05/fast-bit-counting-routines/

#define TWO(c) (0x1u << (c)) #define MASK(c) (((unsigned int)(-1)) / (TWO(TWO(c)) + 1u)) #define COUNT(x,c) ((x) & MASK(c)) + (((x) >> (TWO(c))) & MASK(c))

int bitcount (unsigned int n) { n = COUNT(n, 0) ; n = COUNT(n, 1) ; n = COUNT(n, 2) ; n = COUNT(n, 3) ; n = COUNT(n, 4) ; /* n = COUNT(n, 5) ; for 64-bit integers */ return n ; }

Parallel Count carries out bit counting in a parallel fashion. Consider n after the first line has finished executing. Imagine splitting n into pairs of bits. Each pair contains the number of ones in those two bit positions in the original n. After the second line has finished executing, each nibble contains the number of ones in those four bits positions in the original n. Continuing this for five iterations, the 64 bits contain the number of ones among these sixty-four bit positions in the original n. That is what we wanted to compute.


   1 #! perl
   2 
  25 
  26 sub TWO {    # (c)
  27     ( 0x1 << (shift) );
  28 }
  29 
  30 sub MASK {    #(c)
  31     (
  32         (     # (unsigned int)(-1)
  33             ~0
  34         ) / ( TWO( TWO(shift) ) + 1 )
  35     );
  36 }
  37 
  38 my @Mask;
  39 INIT {
  40     $Mask[$_] = MASK($_) for 0 .. 4;
  41 }
  42 
  43 sub COUNT {    #(x,c)
  44     my ( $x, $c ) = @_;
  45     ( ($x) & $Mask[$c] ) + ( ( ($x) >> ( TWO($c) ) ) & $Mask[$c] );
  46 }
  47 
  48 printf "%d: '%032b' 0x'%X' \n", $_, $Mask[$_], $Mask[$_] for 0 .. 4;
  49 
  50 sub par_mask {    #(unsigned int n)
  51 
  52     my $n = shift;
  53     printf "-: '%032b' \n", $n;
  54 
  55     # $n = COUNT($n, 0) ;
  56     $n = ( ($n) & $Mask[0] ) + ( ( ($x) >> ( 1 << (0) ) ) & $Mask[0] );
  57     printf "%d: '%032b' \n", 0, $n;
  58 
  59     #  $n = COUNT($n, 1) ;
  60     $n = ( ($n) & $Mask[1] ) + ( ( ($x) >> ( 1 << (1) ) ) & $Mask[1] );
  61     printf "%d: '%032b' \n", 1, $n;
  62 
  63     #   $n = COUNT($n, 2) ;
  64     $n = ( ($n) & $Mask[2] ) + ( ( ($x) >> ( 1 << (2) ) ) & $Mask[2] );
  65     printf "%d: '%032b' \n", 2, $n;
  66 
  67     #   $n = COUNT($n, 3) ;
  68     $n = ( ($n) & $Mask[3] ) + ( ( ($x) >> ( 1 << (3) ) ) & $Mask[3] );
  69     printf "%d: '%032b' \n", 3, $n;
  70 
  71     #   $n = COUNT($n, 4) ;
  72     $n = ( ($n) & $Mask[4] ) + ( ( ($x) >> ( 1 << (4) ) ) & $Mask[4] );
  73     printf "%d: '%032b' \n", 4, $n;
  74 
  75     # 	/* n = COUNT(n, 5) ;    for 64-bit integers */
  76     return n;
  77 }
  78 
  79 par_mask( 7 + ( 1 << 8 ) + ( 3 << 24 ) );