Advertisement
homer512

bit counting benchmark

Jun 5th, 2014
192
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.28 KB | None | 0 0
  1. #!/usr/bin/python3
  2.  
  3. """Tests different algorithms to count the number of 1 bits in an integer
  4.  
  5. Python 3.3, Linux x86_64, Intel Core i5 CPU M 450 @ 2.40GHz:
  6.  
  7. str_count        6.04 µs
  8. func_count      43.54 µs
  9. naive_count     19.24 µs
  10. wegner_count     9.21 µs
  11. lut_count        5.21 µs
  12. """
  13.  
  14. import timeit
  15. import time
  16. import random
  17.  
  18.  
  19. def str_count(numbers):
  20.     """Uses string operations"""
  21.     return [bin(number).count('1') for number in numbers]
  22.  
  23.  
  24. def func_count(numbers):
  25.     """Naive counting using bitwise operations and just one statement"""
  26.     return [sum((number & 1 << bit) >> bit
  27.                 for bit
  28.                 in range(number.bit_length()))
  29.             for number in numbers]
  30.  
  31.  
  32. def naive_count(numbers):
  33.     """Naive counting in a loop"""
  34.     def gen():
  35.         for number in numbers:
  36.             count = 0
  37.             while number:
  38.                 count += number & 1
  39.                 number >>= 1
  40.             yield count
  41.     return list(gen())
  42.  
  43.  
  44. def wegner_count(numbers):
  45.     """Method of Peter Wegner in CACM 3 (1960), 322"""
  46.     def gen():
  47.         for number in numbers:
  48.             count = 0
  49.             while number:
  50.                 count += 1
  51.                 number &= number - 1
  52.             yield count
  53.     return list(gen())
  54.  
  55.  
  56. def _gen_lut():
  57.     """Generates a lookup table for lut_count"""
  58.     lut = [0] * 256
  59.     for index in range(256):
  60.         lut[index] = (index & 1) + lut[index >> 1]
  61.     return tuple(lut)
  62.  
  63.  
  64. _lut = _gen_lut()
  65.  
  66.  
  67. def lut_count(numbers):
  68.     """Uses a lookup table
  69.  
  70.    See http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable
  71.    """
  72.     lut = _lut
  73.     def gen():
  74.         for number in numbers:
  75.             count = 0
  76.             while number:
  77.                 count += lut[number & 0xff]
  78.                 number >>= 8
  79.             yield count
  80.     return list(gen())
  81.  
  82.  
  83. def _gen_nums():
  84.     """Creates random integers emphasizing numbers < 1000"""
  85.     distribution = random.expovariate
  86.     lambda_ = 0.001
  87.     return [int(distribution(lambda_)) for _ in range(10000)]
  88.  
  89.  
  90. samples = _gen_nums()
  91.  
  92.  
  93. def test(methods):
  94.     """Checks that given methods for equality against samples"""
  95.     results = (method(samples) for method in methods)
  96.     trusted = next(results)
  97.     wrongs = (method.__name__ for method, result in zip(methods[1:], results)
  98.               if result != trusted)
  99.     for name in wrongs:
  100.         print("%s is wrong" % name)
  101.  
  102.  
  103. def main():
  104.     methods = (str_count, func_count, naive_count, wegner_count, lut_count)
  105.     test(methods)
  106.     methodnames = [method.__name__ for method in methods]
  107.     setups = ("from __main__ import %s, samples" % method
  108.               for method in methodnames)
  109.     statements = ("%s(samples)" % method for method in methodnames)
  110.     number = 10000000 // len(samples)
  111.     times = (timeit.timeit(setup = setup,
  112.                            stmt = statement,
  113.                            number = number,
  114.                            timer = time.process_time,
  115.                        )
  116.              for setup, statement in zip(setups, statements))
  117.     results = ("%s\t%.2f µs" % (method, time) for method, time
  118.                in zip(methodnames, times))
  119.     for result in results:
  120.         print(result)
  121.  
  122.  
  123. if __name__ == '__main__':
  124.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement