Run time optimisation Prime or Not - python

I was tasked to write a program that takes in an input as an integer. If the number is prime the program returns 1 and if the number is not prime the program returns the smallest divisor greater than 1.
def isPrime(n):
if n > 1:
for i in range (2,n):
if (n % i) == 0 :
return i
return 1
I'm trying to improve the run time of this code can i get some help please?

Using the same algorithm, one step you can take to improve the runtime is by optimizing your for loop so that it only checks to the square root of n:
def isPrime(n):
if n > 1:
for i in range (2,int(n ** .5) + 1):
if (n % i) == 0 :
return i
return 1
This will reduce the runtime of your algorithm from O(n) to O(sqrt(n))
Okay, since you asked for an explanation on why we should only check to the square root of n:
Let's say we have a number, 36. The factors of 36 are: 1,2,3,4,6,9,12,18,36
In any case, if the factors of 36 are a and b, so that a * b = 36 and a < b, this inequality will ALWAYS hold true:
a <= sqrt(36) <= b
This means that, if there are no factors of 36 from 2 all the way to the square root of n, no factors will exist that are greater than the square root of n.
The reason we check the square root as well is for numbers like 49, who have no factors other than its square root, 7. This is why we add 1 to the int(n ** .5), because the conversion will round it down, which makes it not inclusive in the for loop.

Related

What is the logic of this process

I was working on a problem in Project Euler; and I found a question in SO. The question and accepted answer says;
n = 600851475143
i = 2
while i * i < n:
while n%i == 0:
n = n / i
i = i + 1
print (n)
It's just awesome. I still can't understand how this process is so fast and can find the largest prime factor of 600billion in 0.00001 seconds. I tried tons of methods and codes for that, processes took over than 1 hour..
Could anyone explain me the logic of this codes and why it's super-fast? is while loop have a special place in Python?
The fundamental theorem of arithmetic states that every integer greater than 1 can be represented as the product of prime numbers. E.g., the number 2100 can be represented like so:
2 x 2 x 3 x 5 x 5 x 7
I've arranged it so the largest prime factor is on the right, in this case 7. What this algorithm is doing is starting from 2 and dividing n (i.e. "removing" that factor) until there are no more to remove (the modulo 0 step checks that it is divisible cleanly before dividing.)
So, following the code, we would have i = 2 and n = 2100, or
2 x 2 x 3 x 5 x 5 x 7
2100 is divisible by 2 (2100 % 2 == 0) and also because we see a 2 in the factorization above. So divide it by 2 and we get 1050, or
2 x 3 x 5 x 5 x 7
Continue dividing by 2, once more, and you get a number that is no longer divisible by 2, that is 525, or
3 x 5 x 5 x 7
Then we increase i to 3 and continue. See how by the end we will be left with the highest prime factor?
The reason for the first while loop's i * i < n (which really should be i * i <= n) is because
if one divisor or factor of a number (other than a perfect square) is greater than its square root, then the other factor will be less than its square root. Hence all multiples of primes greater than the square root of n need not be considered.
from: http://britton.disted.camosun.bc.ca/jberatosthenes.htm
So if i is greater than the square root of n, that means all remaining factors would have had a "pair" that we already found, below the square root of n. The check used, i * i <= n is equivalent but faster than doing a square root calculation.
The reason this is so quick and other brute force methods are so slow is because this is dividing the number down in each step, which exponentially cuts the number of steps that need to be done.
To see this, the prime factorization of 600851475143 is
71 x 839 x 1471 x 6857
and if you modify the code to read:
n = 600851475143
i = 2
while i * i <= n:
while n%i == 0:
print "Dividing by %d" % i
n = n / i
i = i + 1
if n > 1:
print n
You'll see:
>>>
Dividing by 71
Dividing by 839
Dividing by 1471
6857
which shows you that this is exactly how it's working.

Project Euler #23 Incorrect Answer

I have just completed my solution for project euler problem number 23 which states:
A perfect number is a number for which the sum of its proper divisors
is exactly equal to the number. For example, the sum of the proper
divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28
is a perfect number.
A number n is called deficient if the sum of its proper divisors is
less than n and it is called abundant if this sum exceeds n.
As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the
smallest number that can be written as the sum of two abundant numbers
is 24. By mathematical analysis, it can be shown that all integers
greater than 28123 can be written as the sum of two abundant numbers.
However, this upper limit cannot be reduced any further by analysis
even though it is known that the greatest number that cannot be
expressed as the sum of two abundant numbers is less than this limit.
Find the sum of all the positive integers which cannot be written as
the sum of two abundant numbers.
This is my solution:
from math import sqrt
def divisors(n):
for i in range(2, 1 + int(sqrt(n))):
if n % i == 0:
yield i
yield n / i
def is_abundant(n):
return 1 + sum(divisors(n)) > n
abundants = [x for x in range(1, 28123 + 1) if is_abundant(x)]
abundants_set = set(abundants)
def is_abundant_sum(n):
for i in abundants:
if i > n: # assume "abundants" is ordered
return False
if (n - i) in abundants_set:
return True
return False
sum_of_non_abundants = sum(x for x in range(1, 28123 + 1) if not is_abundant_sum(x))
print(sum_of_non_abundants)
My answer is: 3906313
Explanation of my code:
The divisors generator pretty much returns all nontrivial divisors of an integer, but makes no guarantees on the order. It loops through 1 to square root of n and yields the divisor and its quotient. The next function is_abundant actually checks if sum of divisors of n is less than n then return False else return True. Next is the list abundants which holds all the abundant numbers from 1 to 28123 and abundants_set is just like abundants but instead it's a set not a list. The next function is is_abundant_**sum** which pretty much checks if the sum given to the functions is itself abundant or not and in the end the sum of numbers which are not is_abundant_sum is printed.
Where did I do wrong? What's the problem in my code?
Any help would be appreciated.
The divisors generator double counts the factor f of f**2. This bug affects the computed list of abundant numbers.

efficient ways of finding the largest prime factor of a number

I'm doing this problem on a site that I found (project Euler), and there is a question that involves finding the largest prime factor of a number. My solution fails at really large numbers so I was wondering how this code could be streamlined?
""" Find the largest prime of a number """
def get_factors(number):
factors = []
for integer in range(1, number + 1):
if number%integer == 0:
factors.append(integer)
return factors
def test_prime(number):
prime = True
for i in range(1, number + 1):
if i!=1 and i!=2 and i!=number:
if number%i == 0:
prime = False
return prime
def test_for_primes(lst):
primes = []
for i in lst:
if test_prime(i):
primes.append(i)
return primes
################################################### program starts here
def find_largest_prime_factor(i):
factors = get_factors(i)
prime_factors = test_for_primes(factors)
print prime_factors
print find_largest_prime_factor(22)
#this jams my computer
print find_largest_prime_factor(600851475143)
it fails when using large numbers, which is the point of the question I guess. (computer jams, tells me I have run out of memory and asks me which programs I would like to stop).
************************************ thanks for the answer. there was actually a couple bugs in the code in any case. so the fixed version of this (inefficient code) is below.
""" Find the largest prime of a number """
def get_factors(number):
factors = []
for integer in xrange(1, number + 1):
if number%integer == 0:
factors.append(integer)
return factors
def test_prime(number):
prime = True
if number == 1 or number == 2:
return prime
else:
for i in xrange(2, number):
if number%i == 0:
prime = False
return prime
def test_for_primes(lst):
primes = []
for i in lst:
if test_prime(i):
primes.append(i)
return primes
################################################### program starts here
def find_largest_prime_factor(i):
factors = get_factors(i)
print factors
prime_factors = test_for_primes(factors)
return prime_factors
print find_largest_prime_factor(x)
From your approach you are first generating all divisors of a number n in O(n) then you test which of these divisors is prime in another O(n) number of calls of test_prime (which is exponential anyway).
A better approach is to observe that once you found out a divisor of a number you can repeatedly divide by it to get rid of all of it's factors. Thus, to get the prime factors of, say 830297 you test all small primes (cached) and for each one which divides your number you keep dividing:
830297 is divisible by 13 so now you'll test with 830297 / 13 = 63869
63869 is still divisible by 13, you are at 4913
4913 doesn't divide by 13, next prime is 17 which divides 4913 to get 289
289 is still a multiple of 17, you have 17 which is the divisor and stop.
For further speed increase, after testing the cached prime numbers below say 100, you'll have to test for prime divisors using your test_prime function (updated according to #Ben's answer) but go on reverse, starting from sqrt. Your number is divisible by 71, the next number will give an sqrt of 91992 which is somewhat close to 6857 which is the largest prime factor.
Here is my favorite simple factoring program for Python:
def factors(n):
wheel = [1,2,2,4,2,4,2,4,6,2,6]
w, f, fs = 0, 2, []
while f*f <= n:
while n % f == 0:
fs.append(f)
n /= f
f, w = f + wheel[w], w+1
if w == 11: w = 3
if n > 1: fs.append(n)
return fs
The basic algorithm is trial division, using a prime wheel to generate the trial factors. It's not quite as fast as trial division by primes, but there's no need to calculate or store the prime numbers, so it's very convenient.
If you're interested in programming with prime numbers, you might enjoy this essay at my blog.
My solution is in C#. I bet you can translate it into python. I've been test it with random long integer ranging from 1 to 1.000.000.000 and it's doing good. You can try to test the result with online prime calculator Happy coding :)
public static long biggestPrimeFactor(long num) {
for (int div = 2; div < num; div++) {
if (num % div == 0) {
num \= div
div--;
}
}
return num;
}
The naive primality test can be improved upon in several ways:
Test for divisibility by 2 separately, then start your loop at 3 and go by 2's
End your loop at ceil(sqrt(num)). You're guaranteed to not find a prime factor above this number
Generate primes using a sieve beforehand, and only move onto the naive way if you've exhausted the numbers in your sieve.
Beyond these easy fixes, you're going to have to look up more efficient factorization algorithms.
Use a Sieve of Eratosthenes to calculate your primes.
from math import sqrt
def sieveOfEratosthenes(n):
primes = range(3, n + 1, 2) # primes above 2 must be odd so start at three and increase by 2
for base in xrange(len(primes)):
if primes[base] is None:
continue
if primes[base] >= sqrt(n): # stop at sqrt of n
break
for i in xrange(base + (base + 1) * primes[base], len(primes), primes[base]):
primes[i] = None
primes.insert(0,2)
return filter(None, primes)
The point to prime factorization by trial division is, the most efficient solution for factorizing just one number doesn't need any prime testing.
You just enumerate your possible factors in ascending order, and keep dividing them out of the number in question - all thus found factors are guaranteed to be prime. Stop when the square of current factor exceeds the current number being factorized. See the code in user448810's answer.
Normally, prime factorization by trial division is faster on primes than on all numbers (or odds etc.), but when factorizing just one number, to find the primes first to test divide by them later, will might cost more than just going ahead with the increasing stream of possible factors. This enumeration is O(n), prime generation is O(n log log n), with the Sieve of Eratosthenes (SoE), where n = sqrt(N) for the top limit N. With trial division (TD) the complexity is O(n1.5/(log n)2).
Of course the asymptotics are to be taken just as a guide, actual code's constant factors might change the picture. Example, execution times for a Haskell code derived from here and here, factorizing 600851475149 (a prime):
2.. 0.57 sec
2,3,5,... 0.28 sec
2,3,5,7,11,13,17,19,... 0.21 sec
primes, segmented TD 0.65 sec first try
0.05 sec subsequent runs (primes are memoized)
primes, list-based SoE 0.44 sec first try
0.05 sec subsequent runs (primes are memoized)
primes, array-based SoE 0.15 sec first try
0.06 sec subsequent runs (primes are memoized)
so it depends. Of course factorizing the composite number in question, 600851475143, is near instantaneous, so it doesn't matter there.
Here is an example in JavaScript
function largestPrimeFactor(val, divisor = 2) {
let square = (val) => Math.pow(val, 2);
while ((val % divisor) != 0 && square(divisor) <= val) {
divisor++;
}
return square(divisor) <= val
? largestPrimeFactor(val / divisor, divisor)
: val;
}
I converted the solution from #under5hell to Python (2.7x). what an efficient way!
def largest_prime_factor(num, div=2):
while div < num:
if num % div == 0 and num/div > 1:
num = num /div
div = 2
else:
div = div + 1
return num
>> print largest_prime_factor(600851475143)
6857
>> print largest_prime_factor(13195)
29
Try this piece of code:
from math import *
def largestprime(n):
i=2
while (n>1):
if (n % i == 0):
n = n/i
else:
i=i+1
print i
strinput = raw_input('Enter the number to be factorized : ')
a = int(strinput)
largestprime(a)
Old one but might help
def isprime(num):
if num > 1:
# check for factors
for i in range(2,num):
if (num % i) == 0:
return False
return True
def largest_prime_factor(bignumber):
prime = 2
while bignumber != 1:
if bignumber % prime == 0:
bignumber = bignumber / prime
else:
prime = prime + 1
while isprime(prime) == False:
prime = prime+1
return prime
number = 600851475143
print largest_prime_factor(number)
I Hope this would help and easy to understand.
A = int(input("Enter the number to find the largest prime factor:"))
B = 2
while (B <(A/2)):
if A%B != 0:
B = B+1
else:
A = A/B
C = B
B = 2
print (A)
This code for getting the largest prime factor, with nums value of prime_factor(13195) when I run it, will return the result in less than a second.
but when nums value gets up to 6digits it will return the result in 8seconds.
Any one has an idea of what is the best algorithm for the solution...
def prime_factor(nums):
if nums < 2:
return 0
primes = [2]
x = 3
while x <= nums:
for i in primes:
if x%i==0:
x += 2
break
else:
primes.append(x)
x += 2
largest_prime = primes[::-1]
# ^^^ code above to gets all prime numbers
intermediate_tag = []
factor = []
# this code divide nums by the largest prime no. and return if the
# result is an integer then append to primefactor.
for i in largest_prime:
x = nums/i
if x.is_integer():
intermediate_tag.append(x)
# this code gets the prime factors [29.0, 13.0, 7.0, 5.0]
for i in intermediate_tag:
y = nums/i
factor.append(y)
print(intermediate_tag)
print(f"prime factor of {nums}:==>",factor)
prime_factor(13195)
[455.0, 1015.0, 1885.0, 2639.0]
prime factor of 13195:==> [29.0, 13.0, 7.0, 5.0]

Stuck on Project Euler #3 in python

The prime factors of 13195 are 5, 7, 13 and 29. What is the largest
prime factor of the number 600851475143 ?
Ok, so i am working on project euler problem 3 in python. I am kind of confused. I can't tell if the answers that i am getting with this program are correct or not. If somone could please tell me what im doing wrong it would be great!
#import pdb
odd_list=[]
prime_list=[2] #Begin with zero so that we can pop later without errors.
#Define a function that finds all the odd numbers in the range of a number
def oddNumbers(x):
x+=1 #add one to the number because range does not include it
for i in range(x):
if i%2!=0: #If it cannot be evenly divided by two it is eliminated
odd_list.append(i) #Add it too the list
return odd_list
def findPrimes(number_to_test, list_of_odd_numbers_in_tested_number): # Pass in the prime number to test
for i in list_of_odd_numbers_in_tested_number:
if number_to_test % i==0:
prime_list.append(i)
number_to_test=number_to_test / i
#prime_list.append(i)
#prime_list.pop(-2) #remove the old number so that we only have the biggest
if prime_list==[1]:
print "This has no prime factors other than 1"
else:
print prime_list
return prime_list
#pdb.set_trace()
number_to_test=raw_input("What number would you like to find the greatest prime of?\n:")
#Convert the input to an integer
number_to_test=int(number_to_test)
#Pass the number to the oddnumbers function
odds=oddNumbers(number_to_test)
#Pass the return of the oddnumbers function to the findPrimes function
findPrimes(number_to_test , odds)
The simple solution is trial division. Let's work through the factorization of 13195, then you can apply that method to the larger number that interests you.
Start with a trial divisor of 2; 13195 divided by 2 leaves a remainder of 1, so 2 does not divide 13195, and we can go on to the next trial divisor. Next we try 3, but that leaves a remainder of 1; then we try 4, but that leaves a remainder of 3. The next trial divisor is 5, and that does divide 13195, so we output 5 as a factor of 13195, reduce the original number to 2639 = 13195 / 5, and try 5 again. Now 2639 divided by 5 leaves a remainder of 4, so we advance to 6, which leaves a remainder of 5, then we advance to 7, which does divide 2639, so we output 7 as a factor of 2639 (and also a factor of 13195) and reduce the original number again to 377 = 2639 / 7. Now we try 7 again, but it fails to divide 377, as does 8, and 9, and 10, and 11, and 12, but 13 divides 2639. So we output 13 as a divisor of 377 (and of 2639 and 13195) and reduce the original number again to 29 = 377 / 13. As this point we are finished, because the square of the trial divisor, which is still 13, is greater than the remaining number, 29, which proves that 29 is prime; that is so because if n=pq, then either p or q must be less than, or equal to the square root of n, and since we have tried all those divisors, the remaining number, 29, must be prime. Thus, 13195 = 5 * 7 * 13 * 29.
Here's a pseudocode description of the algorithm:
function factors(n)
f = 2
while f * f <= n
if f divides n
output f
n = n / f
else
f = f + 1
output n
There are better ways to factor integers. But this method is sufficient for Project Euler #3, and for many other factorization projects as well. If you want to learn more about prime numbers and factorization, I modestly recommend the essay Programming with Prime Numbers at my blog, which among other things has a python implementation of the algorithm described above.
the number 600851475143 is big to discourage you to use brute-force.
the oddNumbers function in going to put 600851475143 / 2 numbers in odd_list, that's a lot of memory.
checking that a number can be divided by an odd number does not mean the odd number is a prime number. the algorithm you provided is wrong.
there are a lot of mathematical/algorithm tricks about prime numbers, you should and search them online then sieve through the answers. you might also get to the root of the problem to make sure you have squared away some of the issues.
you could use a generator to get the list of odds (not that it will help you):
odd_list = xrange(1, number+1, 2)
here are the concepts needed to deal with prime numbers:
http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
http://en.wikipedia.org/wiki/Primality_test
if you are really stuck, then there are solutions already there:
Project Euler #3, infinite loop on factorization
Project Euler 3 - Why does this method work?
Project Euler Question 3 Help
Here is my Python code:
num=600851475143
i=2 # Smallest prime factor
for k in range(0,num):
if i >= num: # Prime factor of the number should not be greater than the number
break
elif num % i == 0: # Check if the number is evenly divisible by i
num = num / i
else:
i= i + 1
print ("biggest prime number is: "+str(num))
'''
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
'''
import math
def isPrime(x):
if x<2:
return False
for i in range(2,int(math.sqrt(x))):
if not x%i:
return False
return True
def largest_factor(number):
for i in range (2, int(math.sqrt(number))):
if number%i == 0:
number = number/i
if isPrime(number) is True:
max_val = number
break
print max_val
else:
i += 1
return max_val
largest_factor(600851475143)
This actually compiles very fast. It checks for the number formed for being the prime number or not.
Thanks
Another solution to this problem using Python.
def lpf(x):
lpf=2
while (x>lpf):
if (x%lpf==0):
x=x/lpf
else:
lpf+=1
return x
print(lpf(600851475143))
i = 3
factor = []
number = 600851475143
while i * i <= number:
if number % i != 0:
i += 2
else:
number /= i
factor.append(i)
while number >= i:
if number % i != 0:
i += 2
else:
number /= i
factor.append(i)
print(max(factor))
Here is my python code
a=2
list1=[]
while a<=13195: #replace 13195 with your input number
if 13195 %a ==0: #replace 13195 with your input number
x , count = 2, 0
while x <=a:
if a%x ==0:
count+=1
x+=1
if count <2:
list1.append(a)
a+=1
print (max(list1))
Here is my python code:
import math
ma = 600851475143
mn = 2
s = []
while mn < math.sqrt(ma):
rez = ma / mn
mn += 1
if ma % mn == 0:
s.append(mn)
print(max(s))
def prime_max(x):
a = x
i = 2
while i in range(2,int(a+1)):
if a%i == 0:
a = a/i
if a == 1:
print(i)
i = i-1
i = i+1

How do you implement the divisor function in code?

Overall Problem: Project Euler 12 - What is the value of the first triangle number to have over five hundred divisors?
Focus of problem: The divisor function
Language: Python
Description: The function I used is brute and the time it take for the program to find a number with more divisors than x increases almost exponentially with each 10 or 20 numbers highers. I need to get to 500 or more divisors. I've identified that the divisor function is what is hogging down the program. The research I did lead me to divisor functions and specifically the divisor function which is supposed to be a function that will count all the divisors of any integer. Every page I've looked at seems to be directed toward mathematics majors and I only have high-school maths. Although I did come across some page that mentioned allot about primes and the Sieve of Atkins but I could not make the connection between primes and finding all the divisors of any integer nor find anything on the net about it.
Main Question: Could someone explain how to code the divisor function or even provide a sample? Maths concepts make more sense to me when I look at them with code. So much appreciated.
brute force divisor function:
def countdiv(a):
count = 0
for i in range(1,(a/2)+1):
if a % i == 0:
count += 1
return count + 1 # +1 to account for number itself as a divisor
If you need a bruteforce function to calculate Number of Divisors (also known as tau(n))
Here's what it looks like
def tau(n):
sqroot,t = int(n**0.5),0
for factor in range(1,sqroot+1):
if n % factor == 0:
t += 2 # both factor and N/factor
if sqroot*sqroot == n: t = t - 1 # if sqroot is a factor then we counted it twice, so subtract 1
return t
The second method involves a decomposing n into its prime factors (and its exponents).
tau(n) = (e1+1)(e2+1)....(em+1) where n = p1^e1 * p2^e2 .... pm^em and p1,p2..pm are primes
More info here
The third method and much more simpler to understand is simply using a Sieve to calculate tau.
def sieve(N):
t = [0]*(N+1)
for factor in range(1,N+1):
for multiple in range(factor,N+1,factor):
t[multiple]+=1
return t[1:]
Here's it in action at ideone
I agree with the two other answers submitted here in that you will only need to search up to the square root of the number. I have one thing to add to this however. The solutions offered will get you the correct answer in a reasonable amount of time. But when the problems start getting tougher, you will need an even more powerful function.
Take a look at Euler's Totient function. Though it only indirectly applies here, it is incredibly useful in later problems. Another related concept is that of Prime Factorization.
A quick way to improve your algorithm is to find the prime factorization of the number. In the Wikipedia article, they use 36 as an example, whose prime factorization is 2^2 * 3^2. Therefore, knowing this, you can use combinatorics to find the number of factors of 36. With this, you will not actually be computing each factor, plus you'd only have to check divisors 2 and 3 before you're complete.
When searching for divisors of n you never have to search beyond the square root of the number n. Whenever you find a divisor that's less than sqrt(n) there is exactly one matching divisor which is greater than the root, so you can increment your count by 2 (if you find divisor d of n then n/d will be the counterpart).
Watch out for square numbers, though. :) The root will be a divisor that doesn't count twice, of course.
If you're going to solve the Project Euler problems you need some functions that deal with prime numbers and integer factorization. Here is my modest library, which provides primes(n), is_prime(n) and factors(n); the focus is on simplicity, clarity and brevity at the expense of speed, though these functions should be sufficient for Project Euler:
def primes(n):
"""
list of primes not exceeding n in ascending
order; assumes n is an integer greater than
1; uses Sieve of Eratosthenes
"""
m = (n-1) // 2
b = [True] * m
i, p, ps = 0, 3, [2]
while p*p < n:
if b[i]:
ps.append(p)
j = 2*i*i + 6*i + 3
while j < m:
b[j] = False
j = j + 2*i + 3
i += 1; p += 2
while i < m:
if b[i]:
ps.append(p)
i += 1; p += 2
return ps
def is_prime(n):
"""
False if n is provably composite, else
True if n is probably prime; assumes n
is an integer greater than 1; uses
Miller-Rabin test on prime bases < 100
"""
ps = [2,3,5,7,11,13,17,19,23,29,31,37,41,
43,47,53,59,61,67,71,73,79,83,89,97]
def is_spsp(n, a):
d, s = n-1, 0
while d%2 == 0:
d /= 2; s += 1
if pow(a,d,n) == 1:
return True
for r in xrange(s):
if pow(a, d*pow(2,r), n) == n-1:
return True
return False
if n in ps: return True
for p in ps:
if not is_spsp(n,p):
return False
return True
def factors(n):
"""
list of prime factors of n in ascending
order; assumes n is an integer, may be
positive, zero or negative; uses Pollard's
rho algorithm with Floyd's cycle finder
"""
def gcd(a,b):
while b: a, b = b, a%b
return abs(a)
def facts(n,c,fs):
f = lambda(x): (x*x+c) % n
if is_prime(n): return fs+[n]
t, h, d = 2, 2, 1
while d == 1:
t = f(t); h = f(f(h))
d = gcd(t-h, n)
if d == n:
return facts(n, c+1, fs)
if is_prime(d):
return facts(n//d, c+1, fs+[d])
return facts(n, c+1, fs)
if -1 <= n <= 1: return [n]
if n < -1: return [-1] + factors(-n)
fs = []
while n%2 == 0:
n = n//2; fs = fs+[2]
if n == 1: return fs
return sorted(facts(n,1,fs))
Once you know how to factor a number, it is easy to count the number of divisors. Consider 76576500 = 2^2 * 3^2 * 5^3 * 7^1 * 11^1 * 13^1 * 17^1. Ignore the bases and look at the exponents, which are 2, 2, 3, 1, 1, 1, and 1. Add 1 to each exponent, giving 3, 3, 4, 2, 2, 2, and 2. Now multiply that list to get the number of divisors of the original number 76576500: 3 * 3 * 4 * 2 * 2 * 2 * 2 = 576. Here's the function:
def numdiv(n):
fs = factors(n)
f = fs.pop(0); d = 1; x = 2
while fs:
if f == fs[0]:
x += 1
else:
d *= x; x = 2
f = fs.pop(0)
return d * x
You can see these functions at work at http://codepad.org/4j8qp60u, and learn more about how they work at my blog. I'll leave it to you to work out the solution to Problem 12.

Categories

Resources