num = input ()
fact = 0
while fact != num:
fact = fact + 1
rem = num % fact
if rem == 0:
print fact

- 64,563
- 18
- 145
- 216

- 13
- 2
-
2This is a duplicate of [What is the best way to get all the divisors of a number?](http://stackoverflow.com/questions/171765/what-is-the-best-way-to-get-all-the-divisors-of-a-number) – Sven Marnach Nov 11 '10 at 01:03
-
1In general, integer factorization is thought to be a very hard problem. See the [wikipedia entry](https://secure.wikimedia.org/wikipedia/en/wiki/Integer_factorization) for more info and better algorithms. – President James K. Polk Nov 11 '10 at 01:03
-
4Suggested title: "how can I break RSA encryption efficiently?". – Glenn Maynard Nov 11 '10 at 01:11
-
If you like an answer then please upvote, leaving a thanks comment is also nice but an upvote is a better way to say thanks :) – anijhaw Nov 11 '10 at 03:01
-
please select an answer. – robert Nov 11 '10 at 23:42
7 Answers
You only need to go to the square root of the input number to get all the factors (not as far as half the number, as suggested elsewhere). For example, 24 has factors 1, 2, 3, 4, 6, 8, 12, 24. sqrt(24) is approx 4.9. Check 1 and also get 24, check 2 and also get 12, check 3 and also get 8, check 4 and also get 6. Since 5 > 4.9, no need to check it. (Yes, I know 24 isn't the best example as all whole numbers less than sqrt(24) are factors of 24.)
factors = set()
for i in xrange(math.floor(math.sqrt(x))+1):
if x % i == 0:
factors.add(i)
factors.add(x/i)
print factors
There are some really complicated ways to do better for large numbers, but this should get you a decent runtime improvement. Depending on your application, caching could also save you a lot of time.

- 33,242
- 8
- 53
- 74
Use for
loops, for starters. Then, let Python increment for you, and get rid of the unnecessary rem
variable. This code does exactly the same as your code, except in a "Pythonic" way.
num = input()
for x in xrange(1, num):
if (num % x) == 0:
print fact
xrange(x, y)
returns a generator for all integers from x up to, but not including y.

- 75,757
- 21
- 156
- 151
-
If `num` is large, consider `xrange` instead, which creates a generator instead of a list. (Python 3.x `range` always creates a generator.) – Greg Hewgill Nov 11 '10 at 01:04
-
if (num % x) == 0: ZeroDivisionError: integer division or modulo by zero – Preet Sangha Nov 11 '10 at 01:04
-
-
-
So that prints out all the factors of a number? The first obvious optimisation is that you could quit when fact*2 is greater than num. Anything greater than half of num can't be a factor. That's half the work thrown out instantly.
The second is that you'd be better searching for the prime factorisation and deriving all the possible factors from that. There are a bunch of really smart algorithms for that sort of thing.

- 99,986
- 12
- 185
- 204
-
2You only need to search up to sqrt(n), if you have no factors by then there won't be any > sqrt(n) either – John La Rooy Nov 11 '10 at 01:31
-
Oh, good spot. It hadn't dawned on me that if you find one factor, you also simultaneously find another; there may be factors greater than sqrt(n), but n/f for such a factor, f, must be less than sqrt(n) and so f will be a factor you've already found. – Tommy Nov 11 '10 at 01:44
Once you get halfway there (once fact>num/2), your not going to discover any new numbers as the numbers above num/2 can be discovered by calculating num/fact for each one (this can also be used to easily print each number with its pair).
The following code should cust the time down by a few seconds on every calculation and cut it in half where num is odd. Hopefully you can follow it, if not, ask. I'll add more if I think of something later.
def even(num):
'''Even numbers can be divided by odd numbers, so test them all'''
fact=0
while fact<num/2:
fact+=1
rem=num % fact
if rem == 0:
print '%s and %s'%(fact,num/fact)
def odd(num):
'''Odd numbers can't be divided by even numbers, so why try?'''
fact=-1
while fact<num/2:
fact+=2
rem=num % fact
if rem == 0:
print '%s and %s'%(fact,num/fact)
while True:
num=input(':')
if str(num)[-1] in '13579':
odd(num)
else:
even(num)

- 16,327
- 7
- 23
- 21
-
2I thought this was supposed to be a speed competition -- `str(num)[-1] in '13579'` is a baroque and slow way of determining whether `num` is odd; fortunately you do it only once; use `num % 2` or `num & 1` instead. – John Machin Nov 11 '10 at 04:05
Yes. Use a quantum computer
Shor's algorithm, named after mathematician Peter Shor, is a quantum algorithm (an algorithm which runs on a quantum computer) for integer factorization formulated in 1994. Informally it solves the following problem: Given an integer N, find its prime factors.
On a quantum computer, to factor an integer N, Shor's algorithm runs in polynomial time (the time taken is polynomial in log N, which is the size of the input). Specifically it takes time O((log N)3), demonstrating that the integer factorization problem can be efficiently solved on a quantum computer and is thus in the complexity class BQP. This is exponentially faster than the most efficient known classical factoring algorithm, the general number field sieve, which works in sub-exponential time — about O(e1.9 (log N)1/3 (log log N)2/3). The efficiency of Shor's algorithm is due to the efficiency of the quantum Fourier transform, and modular exponentiation by squarings.

- 295,403
- 53
- 369
- 502
-
+1 I highly recommend purchasing a quantum computer if you have the means. – aaronasterling Nov 11 '10 at 05:35
Unfortunately in Python, the divmod operation is implemented as a built-in function. Despite hardware integer division often producing the quotient and the remainder simultaneously, no non-assembly language that I'm aware of has implemented a /%
or //%
basic operator.
So: the following is a better brute-force algorithm if you count machine operations. It gets all factors in O(sqrt(N)) time without having to calculate sqrt(N) -- look, Mum, no floating point!
# even number
fact = 0
while 1:
fact += 1
fact2, rem = divmod(num, fact)
if not rem:
yield fact
yield fact2
if fact >= fact2 - 1:
# fact >= math.sqrt(num)
break

- 81,303
- 11
- 141
- 189