Eulers problem №3, code stucks on big numbers - python

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

Related

python code is not running.I am calculating prime factors of a number (project euler problem - 3)

I am trying to calculate prime factors of a number in python python 3.8.2 32bit (when i pass 35 in code its output should be 7,and so on).But for some reason the program does not return any answer (when i click run the cmd does not output anything).But when i run this javascript, the exact same code works there. (Previously i had an array(list) to which i would append prime factors and at last i would pop the last element which worked for smaller numbers , but for really large numbers i would get a Memory error,so i converted it to use only one variable which will be updated for every while loop). What is going on here ??
My code is :
import math
# Computes only prime factors of n
def compute(n):
arr = 0
# Checks if n is divisible by 2, and if it is divisible,returns 2 because there will be no any other
# prime factor.
if n % 2 == 0:
return 2
# Now that 2 is eliminated we only check for odd numbers upto (square root of n)+1
for i in range(1, round(math.sqrt(n)) + 1, 2):
while n % i == 0:
arr = n/i
n /= i
return str(arr)
print(compute(81))
I am a newbie in python so plz tell me if i have made any silly mistakes.
Ty.
For numbers that are not divisible by 2, your code runs into an infinite loop at
while n%i == 0
For numbers that are divisible by 2, your function returns 2. The execution of the return statement exits the function.
Even if you change the while in while n%i == 0 to if n% == 0 the function will not work.
You will have to restructure your code.
An easy fix would be to check for all factors of a number till n/2 + 1 and return the factors (in a list) that are prime (which can be checked using a separate isprime function.
def isprime(n):
for x in range(2,n//2+1):
if n%x==0:
return False
return True
def compute(n):
arr = []
for i in range(2, n//2+1):
if n % i == 0:
if isprime(i):
arr.append(i)
return arr
If you want all prime factors (which i guess) you shouldn't return values before you have all prime factors in a list for example.
And with this programm you only check once for a 2. But 4 has 2*2. Put it in a loop.
So this code saves all prime factors in a list:
from math import sqrt, ceil
def get_prime_factors(n):
prime_factors = []
while n > 1:
for i in range (2, ceil(sqrt(n))+1):
if n % i == 0:
possible_prime_number = i
while True:
for j in range(2, possible_prime_number//2-1):
if possible_prime_number % j == 0:
possible_prime_number //= j
break
prime_factors.append(possible_prime_number)
n //= possible_prime_number
break
return prime_factors
if you only want the highest one replace return prime_factors with return max(prime_factors)
OK. I think counting upto 600 billion is ridiculous(considering that i am on a 32 bit system). So here is the final code that i am setteling on which gives answer in acceptable time upto 99 million, without using any array and only 1 for loop.
from math import ceil
# Computes only prime factors of n
def compute(n):
arr = 0
# Checks if n is divisible by 2, and if it is divisible,sets arr =2
if n % 2 == 0:
arr = 2
# Now that 2 is eliminated we only check for odd numbers upto (square root of n)+1
for i in range(1, ceil(n/2) + 1, 2):
if n % i == 0:
arr = i
n //= i
return str(arr)
print(compute(999999999))
P.S.:- If you see any possible improvement in my code plz tell me.

Returning largest factor of a number is very slow

When substituting x in the get_large function with a large integer such as 600851475143 the program stalls and doesn't return a value. But, when substituting x with a smaller integer such as 20 it returns the result. How can I fix this?
factors = [] # create new empty list
def calc(x):
for n in range(1, x):
if x % n == 0:
factors.append(n) # if x is divisible by n append to factor list
return factors
def get_large(x):
calc(x) # call the returned values in factors list
return calc(x)[-1] # return the last factor in the list
print("The largest factor is: " + str(get_large(600851475143)))
Here is mine. Note that factors is local to calc() so we aren't constantly appending to the previous list.
Also note that get_large() only has to call calc() once. There is no reason to call it twice.
Finally, I replaced your algorithm in calc() with one that should go substantially faster.
def calc(x):
factors = []
i = 2
while i < x:
while x % i == 0:
x /= i
factors += [i]
i += 1
return factors
def get_large(x):
return calc(x)[-1] #return the last factor in the list
print ("The largest factor is: " +str(get_large(600851475143)))
Result, including timing:
$ time python3 x.py
The largest factor is: 1471
real 0m0.065s
user 0m0.020s
sys 0m0.004s
It's probably not broken, just taking a long time. Python is well known for being slow when running big for loops. I would recommend something like the following:
def calc(x):
n = 2
factors = []
while x != n:
if x % n == 0:
factors.append(n) #if x is divisible by n append to factor list
x = x / n #this will safely and quickly reduce your big number
n = 2 #then start back at the smallest potential factor
else:
n = n + 1
return factors #This will return a list of all prime factors
def get_large(x):
bigFactor = x / calc(x)[0]
#The largest factor is just the original
#number divided by its smallest prime factor
return bigFactor
I used 2 as the smallest potential factor because using 1 would get us nowhere :)
if the number itself is not the largest factor, then why to loop till x, it can looped until x/2 .
[Edited]
import math
def get_large(x):
for n in range(2, math.ceil(math.sqrt(x))):
if x % n == 0:
return x / n
return 1
print ("The largest factor is: " +str(get_large(600851475143)))
Your code is too inefficient and so it takes forever to run for large numbers. The above is a more efficient version.

how to make this code on python run faster?

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

Euler Project #3 in Python

I'm trying to solve the Project Euler problem 3 in Python:
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
I know my program is inefficient and oversized, but I just wanted to know why doesn't it work?
Here's the code:
def check(z):
# checks if the given integer is prime
for i in range(2, z):
if z % i == 0:
return False
break
i = i+1
return True
def primegen(y):
# generates a list of prime integers in the given range
tab = []
while y >= 2:
if check(y) == True:
tab.append(y)
i = i-1
def mainfuntion(x):
# main function; prints the largest prime factor of the given integer
primegen(x)
for i in range(len(tab)):
if x % tab[i] == 0:
print tab[i]
break
mainfuntion(600851475143)
And here's the error:
for i in range(2, z):
OverflowError: range() result has too many items
The reason is that a list in Python is limited to 536,870,912 elements (see How Big can a Python Array Get?) and when you create the range in your example, the number of elements exceeds that number, causing the error.
The fun of Project Euler is figuring out the stuff on your own (which I know you're doing :) ), so I will give one very small hint that will bypass that error. Think about what a factor of a number is - you know that it is impossible for 600851475142 to be a factor of 600851475143. Therefore you wouldn't have to check all the way up to that number. Following that logic, is there a way you can significantly reduce the range that you check? If you do a bit of research into the properties of prime factors, you may find something interesting :)
This is the code that I used!!
n = 600851475143
i = 2
while i * i < n:
while n % i == 0:
n = n / i
i = i + 1
print n
-M1K3
#seamonkey8: Your code can be improved. You can increase it by 2 rather than one. It makes a speed difference for really high numbers:
n,i = 6008514751231312143,2
while i*i <= n:
if n%i == 0:
n //= i
else:
i+=[1,2][i>2]

What's wrong with my python solution to Project Euler #12?

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"

Categories

Resources