Possible Spoiler Warning
I've spent ages trying to improve this algorithm and work out what's going wrong, but I can't seem to work out why the outputted answer is incorrect.
I'm trying to solve Project Euler #12, to get the lowest triangular number to have over 500 divisors, but it says my answer is incorrect.
Here is my Python code:
import time
# function to get the number of divisors
def div(n):
d=2
for i in range(2,int(n**.5)+2):
if (n % i) == 0:
d += 1
return d
start = time.time()
w = True
n=m=1
while w:
n += 1
s = (n*(n+1))/2 # nth triangle number
r = div(s)
if r > m:
m = r
print s,"has",r,"divisors"
if r > 500:
w = False
print "Solved in",((time.time()-start)*1000),"milliseconds"
And the output for that code is this (in 66 seconds):
3 has 2 divisors
6 has 4 divisors
36 has 6 divisors
120 has 9 divisors
...
76576500 has 289 divisors
103672800 has 325 divisors
236215980 has 385 divisors
842161320 has 513 divisors
Solved in 65505.5799484 milliseconds
However, if I input 842161320 into the Project Euler problem, it says it's incorrect.
What am I doing wrong?
I see two bugs:
Your div function is broken: div(24) == 5, while it should be 8
Your 1st triangular number would be 3, although it should be 1
You could implement a working div like this:
import math
def divisors(n):
return sum(1 for x in range(1, n+1) if n % x == 0)
Also, that code is inefficient as hell, some suggestions to improve it are:
Instead of calculating the nth triangular number using your formula, use a rolling sum:
import itertools
s = 0
for i in itertools.count(1):
s += i
if div(s) > 500:
print s
break
Also, Use prime factors to calculate the number of divisors. You can create a prime factor cache for maximum performance.
You are undercounting the total number of divisors. 36, for example, has 9 divisors: 1,2,3,4,6,9,12,18,36. It's true the algorithm only needs to test numbers smaller than sqrt(n) to find all divisors, but you still need to include the implied "large" divisors in your count.
Solved
With the help of Niklas, and changing my div method, I've got the answer. Also, it's now only takes 8% of the time my previous algorithm took.
The algorithm now looks like this:
import time
import itertools
def div(n):
d=0
for i in range(1,int(n**.5)+1):
if (n % i) == 0:
d += 1
return 2*d
start = time.time()
s = m = 0
for i in itertools.count(1):
s += i
r = div(s)
if r > m:
m = r
print s,"has",r,"factors"
if div(s) > 500:
break
print "Solved in",((time.time()-start)*1000),"milliseconds"
Related
I'm currently learning Python, and practice with euler's problem's.
I'm stuck on 3rd problem, my code didn't working on the big numbers, but with other number's it's working.
n = 600851475143
x = 0
for i in range(2,n):
if(n%i == 0):
if(x < i): x = i
print(x)
The console just didn't get any results and stucks.
P.S https://projecteuler.net/problem=3
(sorry for my bad english)
It's running, but just the time it takes is huge.
You can check by the following code, it keeps going to print x's.
n = 600851475143
x = 0
for i in range(2, n):
if n % i == 0:
if x < i:
x = i
print(x)
To save time, you can try the following code instead of your code:
n = 600851475143
x = 0
for i in range(2, n):
if n % i == 0:
x = n // i
break
print(x)
which prints 8462696833 instantly. But as #seesharper stated on the comment, it is merely the largest factor and not a prime factor. So it is not the correct answer to the Project Euler Problem #3.
Check this code you will save a lot of time
Using sqrt for optimization
from math import sqrt
def Euler3(n):
x=int(sqrt(n))
for i in range(2,x+1):
while n % i == 0:
n //= i
if n == 1 or n == i:
return i
return n
n = int(input())
print(Euler3(n))
Also, check my Euler git repo
There are only 6 solutions in python2 and it's pretty old but they are very well optimized.
from tqdm.auto import tqdm
n = 600851475143
x = 0
for i in tqdm(range(2,n)):
if(n%i == 0):
x = i
print(x)
If using classic python, your program will last for at least 40 min, that's why you had no output. I suggest you either use numpy to go through, or add a step because I think even numbers won't work.
I used tqdm to estimate the time needed for the for loop to run, you can download it using pip install tqdm
What would be more efficient is to only divide your number by actual primes. You also only need to check divisors up to the square root of the number given that any valid (integer) result will be also be a divisor (which you will already have checked if your divisor goes beyond the square root).
# generator to obtain primes up to N
# (sieve of Eratosthenes)
def primes(N):
isPrime = [True]*(N+1)
p = 2
while p<=N:
if isPrime[p]:
yield p
isPrime[p::p] = (False for _ in isPrime[p::p])
p += 1 + p>2
# use the max function on primes up to the square root
# filtered to only include those that divide the number
n = 600851475143
result = max(p for p in primes(int(n**0.5)+1) if n%p == 0)
print(result) # 6857
Alternatively, you can use sequential divisions to find factors while reducing the number as you go along. This will cause each new factor you find to be a prime number because divisions by all smaller numbers will already have been done and removed from the remaining number. It will also greatly reduce the number of iterations when your number has many prime factors.
def primeFactors(N): # prime factors generator
d,d2 = 2,4 # start divisors at first prime (2)
while d2<=N: # no need to go beyond √N
if N%d:
d += 1 + (d&1) # progress by 2 from 3 onward
d2 = d*d # use square of d as limiter
else:
yield d # return prime factor
N //= d # and reduce number
if N>1: yield N # final number could be last factor
print(*primeFactors(600851475143)) # 71 839 1471 6857
print(max(primeFactors(600851475143))) # 6857
This question already has answers here:
Least common multiple for 3 or more numbers
(32 answers)
Closed 5 years ago.
This is a Project Euler challenge where I'm trying to find the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
The logic while I came up with seems to run really slowly. It's been running for the last 4 mins and still hasn't found the number. I'm trying to figure out a) Is this logic correct? b) Why does this take so long? and c) Could someone give me a hint on an alternate logic that is more efficient.
# 2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
# What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
smallest_num = 2520
while smallest_num >= 2520:
divisor = 2
while smallest_num % divisor == 0 and divisor < 21:
print("Smalles num = {} and Divisor = {}").format(smallest_num, divisor)
divisor += 1
smallest_num += 1
print("Smallest number is: {}").format(smallest_num)
This is still processing and so far my terminal looks like this
Here's your method run "properly" (using the term liberally), but as #James mentioned it will take an egregious amount of time as a loop.
divisors = np.arange(1, 21)
num = 2520
while True:
if np.all(num % divisors == 0):
print(num)
break
num += 1
A much better method (for Python 3.x). Directly from a similar question:
import functools
import math
functools.reduce(lambda x,y: x*y//math.gcd(x, y), range(1, 21))
Out[27]: 232792560
The following code works fine.
#!/usr/bin/env python
import math
#Generating primes
divisorMax = 20;
top = divisorMax + 1 #divisor max is the upper limit
p = [x for x in range(2,top)]
for num in p:
for idx in range(2,(top//num)+1):
if num*idx in p:
p.remove(num*idx)
#Solving the problem
result = 1;
for i in range(0, len(p)):
a = math.floor(math.log(divisorMax) / math.log(p[i]));
result = result * (p[i]**a);
print(result)
You are using brute force technique to calculate the number, which is easy to understand and write, but takes very much time.
I am using the Prime Factorisation technique explained here.
i am not 100% sure, if my solution is really correct, but i guess it is and it is pretty fast.
First of all, we don't need to care for all divisors, as most are multiples of each other. So best way is to count the divisors backwards, for example starting with 20 down to 1.
I had a look at the prime numbers, the solution needs to be a multiple of all primes above 10, furthermore we need to check the 20 divisor, the rest can be ignored, as when testing divisor 18, the 9 will work as well, and so on.
So i mulitplied 11 * 13 * 17 * 19 * 20. The resulting is 923780 and is divisible by at least the primes + 20.
So i would start at 923780 and test only every 923780th number.
smallest_num = 923780
steps = 923780
while True:
divisor = 19
while smallest_num % divisor == 0 and divisor > 10:
print("Smalles num = {} and Divisor = {}").format(smallest_num, divisor)
divisor -= 1
if divisor == 10:
print("Smallest number is: {}").format(smallest_num)
break
smallest_num += steps
Maybe i have logical error?!
I wrote this snippet on python to resolve project Euler problem #10, but i've been waiting 15 minutes (running this code) and it still doesn't end.
Please help me to improve this code or optimize it.
Here is the snippet:
def prime (n):
f = 1 #flag
for i in range(2,n):
if n % i == 0:
f = 0
return f
s = 0 # Sum
for i in range(2,2000000):
if prime(i) == 1:
s = i + s
print s
import math
def prime (n):
for i in xrange(2, int(math.sqrt(n))+1):
if n % i == 0:
return False
return True
s = 2 # Sum
for i in xrange(3,2000000, 2):
if prime(i):
s += i
print s
It runs in less than 10 seconds for me.
First of all, you want to return from prime once you found out, that a numer is composite.
Second, you do not want to check even numbers. Skip them with xrange(3,2000000, 2)
Third, there is no need to check all numbers from 2 to n in prime, because a*b = b*a
Since you use Python 2 I've replaced range with xrange, it will be a little bit more efficient.
If you want all prime numbers till 2000000, you should consider using Sieve of Eratosthenes.
Code in python : -
def eratosthenes2(n):
multiples = set()
for i in range(2, n+1):
if i not in multiples:
yield i
multiples.update(range(i*i, n+1, i))
print(list(eratosthenes2(2000000)))
Source - http://rosettacode.org/wiki/Sieve_of_Eratosthenes#Python
http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
Polya's conjecture is a mathematical conjecture that suppose that the sum of the first (-1)^(Omega(n)) where Omega(n) is the number of prime divisors of n with multiplicity, is always negative or zero.
A counter example is 906316571, was found fifty years ago. I wonder how could they found it because it takes a massive amount of time, I tried to optimize my python algorithm but it still takes a massive time, Can you help me optimize it ?
Here's my code (I used memoization)
>>> class Memoize:
def __init__(self, f):
self.f = f
self.memo = {}
def __call__(self, *args):
if not args in self.memo:
self.memo[args] = self.f(*args)
return self.memo[args]
>>> def sieve(m):
n=m+1;
s=[];
for i in range(2,n):
s.append(i);
k=0;
while k<len(s):
for i in range(2,int(n/s[k])+1):
x=i*s[k];
if s.count(x)==1:
s.remove(x);
k=k+1;
return s;
>>> s=sieve(100000);
>>> def omega(n):
k=0;
if n==1:
return 0;
else :
while k<len(s) and n%s[k]!=0 :
k=k+1;
if k<len(s):
return omega(int(n/s[k]))+1;
else :
return 1;
>>> omega=Memoize(omega)
>>> def polya(n):
h=omega(n);
if n==1:
return 0;
else :
if omega(n)%2==0:
return polya(n-1)+1;
else :
return polya(n-1)-1;
>>> polya=Memoize(polya);
>>> while polya(k)<=0 :
k=k+1;
As chepner told you, the original year 1958 proof was not done with brute force. Neither did it reveal the smallest number to break the rule, it was only found in 1980. I have not studied the case at all, but the 1980 proof may be have been done with a computer. It is more a question of the amount of RAM available, not a question of processing speed as such.
However, with modern computers it should not be overtly difficult to approach the problem with brute force. Python is not the best alternative here, but still the numbers can be found in a reasonable time.
import numpy as np
import time
max_number = 1000000000
# array for results
arr = np.zeros(max_number, dtype='int8')
# starting time
t0 = time.time()
# some tracking for the time spent
time_spent = []
# go through all possible numbers up to the larges possible factor
for p in range(2, int(np.sqrt(max_number))):
# if the number of factors for the number > 0, it is not a prime, jump to the next
if arr[p] > 0:
continue
# if we have a prime, we will have to go through all its powers < max_number
n = p
while n < max_number:
# increment the counter at n, 2n, 3n, ...
arr[n::n] += 1
# take the next power
n = n * p
# track the time spent
print "Time spent calculating the table of number of factors: {0} s".format(time.time()-t0)
# now we have the big primes left, but their powers are not needed any more
# they need to be taken into account up to max_number / 2
j = 0
for p in range(p + 1, (max_number + 1) / 2):
if arr[p] > 0:
continue
arr[p::p] += 1
if j % 10000 == 0:
print "{0} at {1} s".format(p, time.time()-t0)
j += 1
print "Primes up to {0} done at {1} s".format(p, time.time()-t0)
# now we have only big primes with no multiples left, they will be all 1
arr[arr == 0] = 1
print "Factor table done at {0} s".format(time.time() - t0)
# calculate the odd/even balance, note that 0 is not included and 1 has 0 factors
cumulative = np.cumsum(1 - 2 * (arr[1:] & 1), dtype='int32')
print "Total time {0} s".format(time.time()-t0)
This is not the fastest or the most optimized function, the mathematics behind this should be quite obvious. In my machine (i7) running on one core it takes approximately 2800 seconds to calculate the full table of number of prime factors up to 1 x 10^9. (But beware, do not try this without 64-bit python and at least 8 GB RAM. The cumulative sum table consumes 4 GB.)
To prove that the above function works at least quite well, here is a plot of the interesting area:
Due to some problems with the first numbers, the results given by the code above are slightly off. To get the official summatory Liouville lambda, use cumulative[n-1] + 2. For the number mentioned in the question (906 316 571) the result is cumulative[906316570] + 2 equalling to 829, which is the maximum value in the region.
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