@@ -60,27 +60,72 @@ def get_set_bits_count_using_modulo_operator(number: int) -> int:
6060 return result
6161
6262
63+ def get_set_bits_count_using_lookup_table (number : int ) -> int :
64+ """
65+ Count the number of set bits in a 32-bit integer using a precomputed lookup table.
66+ >>> get_set_bits_count_using_lookup_table(25)
67+ 3
68+ >>> get_set_bits_count_using_lookup_table(37)
69+ 3
70+ >>> get_set_bits_count_using_lookup_table(21)
71+ 3
72+ >>> get_set_bits_count_using_lookup_table(58)
73+ 4
74+ >>> get_set_bits_count_using_lookup_table(0)
75+ 0
76+ >>> get_set_bits_count_using_lookup_table(256)
77+ 1
78+ >>> get_set_bits_count_using_lookup_table(-1)
79+ Traceback (most recent call last):
80+ ...
81+ ValueError: the value of input must not be negative
82+ """
83+ _LOOKUP_TABLE = [bin (i ).count ("1" ) for i in range (256 )]
84+
85+ if number < 0 :
86+ raise ValueError ("the value of input must not be negative" )
87+
88+ # Split 32-bit number into four 8-bit chunks and use lookup table
89+ return (
90+ _LOOKUP_TABLE [number & 0xFF ]
91+ + _LOOKUP_TABLE [(number >> 8 ) & 0xFF ]
92+ + _LOOKUP_TABLE [(number >> 16 ) & 0xFF ]
93+ + _LOOKUP_TABLE [(number >> 24 ) & 0xFF ]
94+ )
95+
96+
97+
6398def benchmark () -> None :
6499 """
65- Benchmark code for comparing 2 functions, with different length int values.
66- Brian Kernighan's algorithm is consistently faster than using modulo_operator.
100+ Benchmark code for comparing 3 functions, with different length int values.
101+ Brian Kernighan's algorithm is consistently faster than using modulo_operator,
102+ and the lookup table method is often the fastest for repeated calls.
67103 """
68104
69105 def do_benchmark (number : int ) -> None :
70106 setup = "import __main__ as z"
71107 print (f"Benchmark when { number = } :" )
108+
72109 print (f"{ get_set_bits_count_using_modulo_operator (number ) = } " )
73110 timing = timeit (
74111 f"z.get_set_bits_count_using_modulo_operator({ number } )" , setup = setup
75112 )
76113 print (f"timeit() runs in { timing } seconds" )
114+
77115 print (f"{ get_set_bits_count_using_brian_kernighans_algorithm (number ) = } " )
78116 timing = timeit (
79117 f"z.get_set_bits_count_using_brian_kernighans_algorithm({ number } )" ,
80118 setup = setup ,
81119 )
82120 print (f"timeit() runs in { timing } seconds" )
83121
122+ print (f"{ get_set_bits_count_using_lookup_table (number ) = } " )
123+ timing = timeit (
124+ f"z.get_set_bits_count_using_lookup_table({ number } )" ,
125+ setup = setup ,
126+ )
127+ print (f"timeit() runs in { timing } seconds" )
128+
84129 for number in (25 , 37 , 58 , 0 ):
85130 do_benchmark (number )
86131 print ()
0 commit comments