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.
Related
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.
I'm currently trying to solve Project Euler problem 3 using python, which is trying to find the largest prime factor of a number. The method I'm using is essentially brute forcing my way through each integer less than the integer in question, checking if it's a factor of said integer, and then checking if it is prime. However, for some reason, my code doesn't seem to be working.
I've tried to use create a function which goes through each integer (i) less than a given integer (n), and if i is divisible by n, the function then proceeds to check if i is a prime number by going through every integer less or equal to i (x). if x is a factor of i, then the value is added to a zero-integer defined as (a). After that, if a ends up adding to equal i + 1, then that means the factor is prime, since the only numbers divisible were itself and 1. The code is as below:
def primefactor(n):
for i in range(1, n+1): #goes through each integer less than n
if n % i == 0: #checks if integer is a factor
for x in range(1, i+1): #another loop to check if the factor is prime
a = 0
primenumbers = []
if i % x == 0:
a += x
if a == i + 1:
primenumbers.append(i)
print(primenumbers)
primefactor(13195)
What i expected the output to be was for it to print a list of all of the prime factors of the number, in this case, [5, 7, 13, 29], but instead, all I got was an empty list, []
This issue with your code is you assign primenumbers to an empty list each iteration with primenumbers = [].
Also if you don't want to brute force it, a good method to solve solutions like this is to google a formula such as Formula for primes and you will find:
By Wilson's theorem, n+1 is prime if and only if n! mod(n + 1) = n.
So you can do something like this:
# This is just used as caching to make it faster
# it is not needed.
from functools import lru_cache
from math import factorial
#lru_cache()
def isprime(x):
n = x - 1
if n == factorial(n) % (n + 1):
return True
else:
return False
def primefactor(n):
primenumbers = []
for i in range(1, n + 1): #goes through each integer less than n
if n % i == 0: #checks if integer is a factor
isprime(i) and primenumbers.append(i)
print(primenumbers)
primefactor(13195)
Output:
[1, 5, 7, 13, 29]
There are also significantly faster solutions then this such that does go through all numbers 0 to n:
Algorithm to find Largest prime factor of a number
Project Euler problem 50 reads as follows:
The prime 41, can be written as the sum of six consecutive primes:
41 = 2 + 3 + 5 + 7 + 11 + 13
This is the longest sum of consecutive primes that adds to a prime below one-hundred.
The longest sum of consecutive primes below one-thousand that adds to a prime, contains 21 terms, and is equal to 953.
Which prime, below one-million, can be written as the sum of the most consecutive primes?
In my approach I pregenerate a list of primes using sieve of eratosthenes, then
in the function itself I keep adding succeeding elements of my prime number list
and each time i do that I check if the sum itself is prime and if it is I keep track of it as the biggest one and return it. Well that should work i guess ? Obviously the answer is incorrect, but the interesting thing is that when i change the sieve to generate primes below 100000 it doesn't give an index error but gives another result.
from algorithms import gen_primes
primes = [i for i in gen_primes(1000000)]
def main(n):
idx, total, maximum = 0, 0, 0
while total < n:
total += primes[idx]
idx += 1
if total in primes:
maximum = total
return maximum
print(main(1000000))
Your program doesn't solve the general problem: you always start your list of consecutive primes at the lowest, 2. Thus, what you return is the longest consecutive list starting at 2*, rather than any consecutive list of primes.
In short, you need another loop ...
start_idx = 0
while start_idx < len(primes) and best_len*primes[start_idx] < n:
# find longest list starting at primes[start_idx]
start_idx += 1
In case it's any help, the successful sequence begins between 1500 and 2000.
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.
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