Skip to content

Commit

Permalink
ENH: Added popcount implementation for big python ints natively
Browse files Browse the repository at this point in the history
[1/2] `popcount` object loop changes
  • Loading branch information
ganesh-k13 committed Jul 2, 2021
1 parent 8a9b6ef commit 8bcabf1
Showing 1 changed file with 36 additions and 0 deletions.
36 changes: 36 additions & 0 deletions numpy/core/_internal.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,24 @@ def _usefields(adict, align):
"offsets": offsets,
"titles": titles}, align)

_INT_SHIFT = 30
_MASK = (2 ** _INT_SHIFT)

# Get the internal ob_digit representation of python integer
# Ref: https://rushter.com/blog/python-integer-implementation/
def _get_ob_digit_array(num):
t = abs(num)

num_list = []
while t != 0:
# Get remainder from division
small_int = t % _MASK # more efficient bitwise analogue: (t & (MASK-1))
num_list.append(small_int)

# Get integral part of the division (floor division)
t = t // _MASK # more efficient bitwise analogue: t >>= SHIFT

return num_list

# construct an array_protocol descriptor list
# from the fields attribute of a descriptor
Expand Down Expand Up @@ -793,6 +811,24 @@ def _gcd(a, b):
def _lcm(a, b):
return a // _gcd(a, b) * b

def _popcount64(a):
""" Computes the number of 1-bits in a (64 bits) """

# Refer to npy_math_internal.h.src for more details.
a = abs(a)
a -= ((a >> 1) & 0x5555555555555555)
a = (a & 0x3333333333333333) + (a >> 2 & 0x3333333333333333)
return (((a + (a >> 4)) & 0xf0f0f0f0f0f0f0f) * 0x101010101010101 >> 56) & 0xff

def _bit_count(a):
""" Computes the number of 1-bits in a (Python Integer) """
res = 0

for i in _get_ob_digit_array(a):
res += _popcount64(i)

return res

def array_ufunc_errmsg_formatter(dummy, ufunc, method, *inputs, **kwargs):
""" Format the error message for when __array_ufunc__ gives up. """
args_string = ', '.join(['{!r}'.format(arg) for arg in inputs] +
Expand Down

0 comments on commit 8bcabf1

Please sign in to comment.