Factoring the powers of 2 in Python The powers of 2 are trivial to factor because all powers of 2 have one 1-bit and the rest 0-bits. Just iterate minus one 0-bit as follows: 10000,1000,100,10,1. And then convert the binary strings into base-10 and you got the factors for powers of 2.

Example

import operator
from operator import mul
from functools import reduce
import time

print('Find the factors of a power of 2')
print('This input number must be a power of 2')
X = 32

binary = "{0:b}".format(int(X))
l = len(binary)

# Checking if input is power of 2
# All binary strings that are a power of 2 must
# have only ONE 1 bit

if binary.count(str(1)) == 1:
  print('yes, this is a power of two')
else:
  print('no, this is not a power of 2')
  quit()  

start = (round(time.time() * 1000000))
count = 0
result = [];
for j in range(0, l):
        count = count + 1
        # create list of factors called result
        result.append(int(binary[0:l-count], 2))
        if len(result) == l-1:
          # I don't want to forget X itself is a factor
          result.append(X)
          end = (round(time.time() * 1000000))
          break

print(result)          
print('Factoring took', end-start, 'microseconds')


Output



Find the factors of a power of 2
This input number must be a power of 2
yes, this is a power of two
[16, 8, 4, 2, 1, 32]
Factoring took 0 microseconds


Question

What better names could I use to define my variables, and what could make the program run faster?

Is there a more efficient implementation to decide if a number is a power of 2?
There should be some function definitions. is_power_of_2, powers_of_2_below and a main.
It's good practice to use an if __name__ == '__main__' guard.
Please stop putting lots of spaces at the end of lines.
Many of the imports are not used.
Always indent with 4 spaces.


import time


def is_power_of_2(X):
    binary = "{0:b}".format(int(X))
    return binary.count(str(1)) == 1


def powers_of_2_below(X):
    binary = "{0:b}".format(int(X))
    l = len(binary)
    count = 0
    result = [];
    for j in range(0, l):
        count = count + 1
        # create list of factors called result
        result.append(int(binary[0:l-count], 2))
        if len(result) == l-1:
            # I don't want to forget X itself is a factor
            result.append(X)
            break
    return result


def main(X):
    print('Find the factors of a power of 2')
    print('This input number must be a power of 2')
    if is_power_of_2(X):
        print('yes, this is a power of two')
    else:
        print('no, this is not a power of 2')
        quit()
    start = (round(time.time() * 1000000))
    result = factors_of_power_of_2(X)
    end = (round(time.time() * 1000000))
    print(result)
    print('Factoring took', end - start, 'microseconds')


if __name__ == '__main__':
    main(X)



You can now use return rather than quit to exit main.
The code in is_power_of_2 is fine. There are a couple other ways you can implement it but they're all pretty underwhelming.
By replacing count with (j + 1) we can remove the need for that variable.
By using j rather than (j + 1) we can remove the need for the if in the for.
To get l in powers_of_2_below we can use X.bit_length().
We can instead use 1 &lt;&lt; j to build the value from j alone. This however will invert the output.


import time


def is_power_of_2(x):
    binary = "{0:b}".format(int(x))
    return binary.count(str(1)) == 1


def powers_of_2_below(x):
    result = []
    for j in range(0, x.bit_length()):
        result.append(1 &lt;&lt; j)
    return result


def main(x):
    print('Find the factors of a power of 2')
    print('This input number must be a power of 2')
    if is_power_of_2(x):
        print('yes, this is a power of two')
    else:
        print('no, this is not a power of 2')
        return
    start = (round(time.time() * 1000000))
    result = factors_of_power_of_2(x)
    end = (round(time.time() * 1000000))
    print(result)
    print('Factoring took', end - start, 'microseconds')


if __name__ == '__main__':
    main(32)



We can use a list comprehension instead of a for loop in powers_of_2_below.

def powers_of_2_below(x):
    return [1 &lt;&lt; j for j in range(x.bit_length())]



Alternate solutions to is_power_of_2:


We can use powers_of_2_below with &amp; and any.

def is_power_of_2(x):
    x = abs(x)
    if x == 0:
        return False
    return not any(x &amp; i for i in powers_of_2_below(x - 1))

We can replace the any with just x &amp; x - 1. This is because \$1000 - 1 = 0111\$. Logically this is doing exactly the same as 13.

def is_power_of_2(x):
    x = abs(x)
    if x == 0:
        return False
    return not x &amp; x - 1

We can instead use x.bit_length() to construct the power of 2 it should be and check they are the same.

def is_power_of_2(x):
    if x == 0:
        return False
    return abs(x) == 1 &lt;&lt; x.bit_length() - 1



Overall is_power_of_2 just doesn't look nice.