Halve a number in a single line

Viewed 74

What I'm trying to achieve:

l = []
n = 100
while (n):
    l.append(n//2)
    n //= 2
    
print(l)
# [50, 25, 12, 6, 3, 1, 0]

What I've tried:

>>> from itertools import takewhile
>>> n = 100
>>> [(n := n//2) for _ in takewhile(lambda x: x > 0, [n] * n)]
[50, 25, 12, 6, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, ... 0, 0, 0]

This clearly doesn't work, and I also don't like the idea of creating an array of size n...

2 Answers
from math import log2, floor
n = 100
l = [n//(2**x) for x in range(1, floor(log2(n))+2)]

This will leave l as [50, 25, 12, 6, 3, 1, 0]. If you don't want the 0, change the +2 to +1.

You can use numpy to get vectorized solution:

import numpy as np

n= 100

arr = np.array(n * np.ones(int(np.log(n)/np.log(2))))

arr = np.floor(arr / 2**(np.arange(len(arr)) + 1))

Outputs:

[50. 25. 12.  6.  3.  1.]

Brief explanation:

  1. Size of array you're looking for is: log_2(n), which I calculate from: int(np.log(n)/np.log(2)) which in essence returns highest integer exponent satisfying the inequality: 2^x < n

  2. Then you can just restate the problem as sum[i=1 to x](n//2^i)

Related