Last active
November 3, 2025 03:19
-
-
Save sithumonline/de88ec7f90f4c95c14f0685da6298b4f to your computer and use it in GitHub Desktop.
Hamming weight with LRU Caching
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| import sys | |
| from datetime import datetime, timedelta | |
| from collections import OrderedDict | |
| from functools import wraps | |
| def cached(n: int = 100, ttl: int = 10): | |
| def _decorate(func): | |
| store = OrderedDict() | |
| @wraps(func) | |
| def _wrapper(*args, **kwargs): | |
| k = (args, tuple(sorted(kwargs.items()))) | |
| now = datetime.now() | |
| item = store.get(k) | |
| # print(f"key: {k}, now: {now}, item: {item}") | |
| if item is not None: | |
| value, expires_at = item | |
| if now < expires_at: | |
| store.move_to_end(k) | |
| return value | |
| value = func(*args, **kwargs) | |
| store[k] = (value, now + timedelta(seconds=ttl)) | |
| store.move_to_end(k) | |
| if len(store) > n: | |
| store.popitem(last=False) | |
| return value | |
| return _wrapper | |
| return _decorate | |
| """ | |
| //types and constants used in the functions below | |
| //uint64_t is an unsigned 64-bit integer variable type (defined in C99 version of C language) | |
| const uint64_t m1 = 0x5555555555555555; //binary: 0101... | |
| const uint64_t m2 = 0x3333333333333333; //binary: 00110011.. | |
| const uint64_t m4 = 0x0f0f0f0f0f0f0f0f; //binary: 4 zeros, 4 ones ... | |
| const uint64_t m8 = 0x00ff00ff00ff00ff; //binary: 8 zeros, 8 ones ... | |
| const uint64_t m16 = 0x0000ffff0000ffff; //binary: 16 zeros, 16 ones ... | |
| const uint64_t m32 = 0x00000000ffffffff; //binary: 32 zeros, 32 ones | |
| const uint64_t h01 = 0x0101010101010101; //the sum of 256 to the power of 0,1,2,3... | |
| """ | |
| m1 = 0x5555555555555555 | |
| m2 = 0x3333333333333333 | |
| m4 = 0x0F0F0F0F0F0F0F0F | |
| m8 = 0x00FF00FF00FF00FF | |
| m16 = 0x0000FFFF0000FFFF | |
| m32 = 0x00000000FFFFFFFF | |
| h01 = 0x0101010101010101 | |
| # This is a naive implementation, shown for comparison, | |
| # and to help in understanding the better functions. | |
| # This algorithm uses 24 arithmetic operations (shift, add, and). | |
| def popcount64a(x: int) -> int: | |
| x = (x & m1) + ((x >> 1) & m1) # put count of each 2 bits into those 2 bits | |
| x = (x & m2) + ((x >> 2) & m2) # put count of each 4 bits into those 4 bits | |
| x = (x & m4) + ((x >> 4) & m4) # put count of each 8 bits into those 8 bits | |
| x = (x & m8) + ((x >> 8) & m8) # put count of each 16 bits into those 16 bits | |
| x = (x & m16) + ((x >> 16) & m16) # put count of each 32 bits into those 32 bits | |
| x = (x & m32) + ((x >> 32) & m32) # put count of each 64 bits into those 64 bits | |
| return x | |
| @cached(n=100, ttl=10) | |
| def ones(x: int) -> int: | |
| MAX = 2**64 - 1 | |
| if x > MAX or x < 0: | |
| raise ValueError(f"Unacceptable input: {x}") | |
| return popcount64a(x) | |
| def main() -> int: | |
| for x in [3, 5, 0, 255, 5, 256, -3]: | |
| try: | |
| print(ones(x)) | |
| except Exception as e: | |
| print(f"[ERROR] ones ({e})") | |
| return 0 | |
| if __name__ == "__main__": | |
| sys.exit(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment