Project Euler #10 (Python) - python

Why is my algorithm for finding the sum of all prime numbers below 2 million so slow?
I'm a fairly beginner programmer and this is what I came up with for finding the solution:
import time
sum = 2
start = time.time()
for number in range(3, 2000000):
prime = True
for x in range(2, number):
if number % x == 0:
prime = False
if prime:
sum += number
print "Sum =", sum
end = time.time() - start
print "Runtime =", end
Can someone please help me out?
Thanks!

Your algorithm uses trial division, which is very slow. A better algorithm uses the Sieve of Eratosthenes:
def sumPrimes(n):
sum, sieve = 0, [True] * n
for p in range(2, n):
if sieve[p]:
sum += p
for i in range(p*p, n, p):
sieve[i] = False
return sum
print sumPrimes(2000000)
That should run in less than a second. If you're interested in programming with prime numbers, I modestly recommend this essay at my blog.

There are many optimisations that you could do (and should do since you will need prime generation for many of the problems in project Euler, so having a fast implementation simplifies things later on).
Take a look at the sieve of Atkin (and related sieves) (http://en.wikipedia.org/wiki/Sieve_of_Atkin) to get an understanding of how prime generation can be speeded up over brute force (algorithmically that is).
Then take a look at the awesome answer to this S.O.-post (Fastest way to list all primes below N) that clocks a number of prime generation algorithms/implementations.

Nobody pointed this out, but using range in Python 2.x is very slow. Use xrange instaed, in this case this should give you a huge performance advantage.
See this question.
Also, you don't have to loop until the number you check, checking until round(sqrt(n)) + 1 is sufficient. (If the number greater than its square divides it, there's a number smaller than the square that you must have already noticed.)

You need to use prime sieve check out eratostheneses sieve and try to implement it in code.
Trial division is very inefficient for finding primes because it has complexity n square, the running time grows very fast. This task is meant to teach you how to find something better.

First off, you're looping over too many numbers. You don't need to check if EVERY number less than a given number is a divisor to check if a number is prime (I'll let you figure out why this is yourself). You are running hundreds of billions of loops, where hundreds of millions will do.
Something like this works faster, but is by no means optimal:
value=2
for i in range(3, 2000000):
prime=True
if i%2 != 0:
for j in range(3, int(round(sqrt(i)+1)),2):
if i % j==0:
prime=False
else:
prime=False
if prime==True:
value+=i
print value

First of all, I think you can split your code by defining a function. However, there is a drawback of using a regular function in this case because every time a normal function return a value, the next call to the function will execute the complete code inside the function again. Since you are iterating 2 million times, it would be better to:
Have a function that gives you the next prime number and provisionally returns the control to the caller. Such functions are known as GENERATORS.
To define a generator function just use the yield command instead of return.
When you use generators , it is like knowing that the function will be called again and when it happens the execution inside the function continues right after the yield instruction instead of going over the whole function again.
The advantage of this approach is that on the long run of an iterator you avoid the consumption all of the system's memory.
I recommend you to have a look at this article about generators in python. It provides a more extensive explanation for this example.
The solution would be something like this:
import math
# Check if a number is prime
def is_prime(number):
if number > 1:
if number == 2:
return True
if number % 2 == 0:
return False
for current in range(3, int(math.sqrt(number) + 1), 2):
if number % current == 0:
return False
return True
return False
# Get the next after a given number
def get_primes(number):
while True:
if is_prime(number):
yield number
# Next call to the function will continue here!
number += 1
# Get the sum of all prime numbers under a number
def sum_primes_under(limit):
total = 2
for next_prime in get_primes(3):
if next_prime < limit:
total += next_prime
else:
print(total)
return
# Call the function
sum_primes_under(2000000)

This question gives output quite very fast when you use sieve of eratosthenes Link to it. You can make it even more faster with a little modification like iterating the whole 2 million numbers just half times by considering only the odd numbers. This way you can save lots of time.
n = 2000000
ar = [False for x in range(n)]
sum = 2
def mul(a):
i = 2;p = i*a
while (p < n):
ar[p] = 1
++i
p = i*a
while (x < n):
if(ar[x] == 0):
sum += x;mul(x)
x += 2
print (sum)
Here you can see the same algorithm in c++:-
#include<bits/stdc++.h>
using namespace std;
const int n = 2000000;
bool ar[n];
void mul(int a)
{
int i = 2;int p = i*a;
while(p < n)
{
ar[p] = 1;
++i;p = i*a;
}
}
long long sieve()
{
long long sum = 2;
for(int i = 3;i < n;i += 2)
{
if(ar[i] == 0)
sum += i,mul(i);
}
return sum;
}
int main()
{
cout<<sieve();
return 0;
}
C++ works around 10 times faster than python anyways and for this algorithm too.

sum = 2
def isPrime(n):
if n % 2 == 0: return False
for i in range(3, int(n**0.5)+1, 2):
if n % i == 0: return False
return True
if __name__ == "__main__":
n = 1
while n < 2000000:
n += 2
if isPrime(n):sum += n
print sum

import time
start = time.time()
def is_prime(num):
prime = True
for i in range(2,int(num**0.5)+1):
if num % i == 0:
prime = False
break
return prime
sum_prime = 0
for i in range(2,2000000):
if is_prime(i):
sum_prime += i
print("sum: ",sum_prime)
elapsed = (time.time() - start)
print("This code took: " + str(elapsed) + " seconds")

Related

Most efficient way to filter prime numbers from a list of random numbers in Python

I have a list filled with random numbers and I want to return the prime numbers from this list. So I created these functions:
def is_prime(number):
for i in range(2, int(sqrt(number)) + 1):
if number % i == 0:
return False
return number > 1
And
def filter_primes(general_list):
return set(filter(is_prime, general_list))
But I want to improve performance, so how can I achieve this?
Sieve of Eratosthenes, taking about 0.17 seconds for primes under 10 million on PyPy 3.5 on my device:
from array import array
from math import isqrt
def primes(upper):
numbers = array('B', [1]) * (upper + 1)
for i in range(2, isqrt(upper) + 1):
if numbers[i]:
low_multiple = i * i
numbers[low_multiple:upper + 1:i] = array('B', [0]) * ((upper - low_multiple) // i + 1)
return {i for i, x in enumerate(numbers) if i >= 2 and x}
and the filter function:
filter_primes = primes(10_000_000).intersection
3 rounds of the the Miller-Rabin test ( https://en.wikipedia.org/wiki/Miller%2dRabin_primality_test ) using bases 2, 7, and 61, is known to accurately detect all primes <= 32 bit, i.e., anything that fits into a python int.
This is much, much faster than trial division or sieving if the numbers can be large.
If the numbers cannot be large (i.e., < 10,000,000 as you suggest in comments), then you may want to precompute the set of all primes < 10,000,000, but there are over 600,000 of those.
How about this? I think It's a little better:
def filter_primes(general_list):
return filter(is_prime, set(general_list))
This way we don't call is_prime() for same number multiple times.
The Sieve of Eratosthenes is more efficient than Trial Division, the method you are using.
Your trial division loop can be made more efficient, taking about half the time. Two is the only even prime number, so treat two as a special case and only deal with odd numbers thereafter, which will halve the work.
My Python is non-existent, but this pseudocode should make things clear:
def isPrime(num)
// Low numbers.
if (num <= 1)
return false
end if
// Even numbers
if (num % 2 == 0)
return (num == 2) // 2 is the only even prime.
end if
// Odd numbers
for (i = 3 to sqrt(num) + 1 step 2)
if (num % i == 0)
return false
end if
end for
// If we reach here, num is prime.
return true;
end def
That step 2 in the for loop is what halves the work. Having earlier eliminated all even numbers you only need to test with odd trial divisors: 3, 5, 7, ...
def primes_list(num_list):
divs = [2,3,5,7]
primes = [x for x in set(num_list) if 0 not in {1 if ((x%i != 0) | (x in divs)) & (x > 0) else 0 for i in divs}]
return primes
For this function, it takes a list, num_list, as a parameter. divs is a predefined, or rather hard coded, list of prime numbers less than 10 excluding 1. Then we use list comprehension to filter num_list for prime numbers as the variable primes.
This is one more flavour of code to find the prime no of the range. The simple and easy way.
def find_prime(n):
if n <=1:
return False
else:
for i in range(2, n):
if n % i == 0:
return False
return True
n = 10
x = filter(find_prime, range(n)) #you can give random no list too
print(list(x))
def is_prime(n):
if n>1:
for i in range(2,int(n**0.5)+1):
if n%i==0:
return False
return True
else: return False
print([x for x in general_list if is_prime(x)])
would you try this... There is no need for the filter at all and you could simply apply set() to the general_list if there are duplicate elements in the list to optimize more.

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]

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]

Python "OverflowError" [duplicate]

This question already has answers here:
`xrange(2**100)` -> OverflowError: long int too large to convert to int
(5 answers)
Closed 13 days ago.
I am just starting to learn to code in Python. I am trying to write some code to answer this Project Euler Question:
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
My program works with the test case of 13195, but when I try to enter 600851475143, I get the error: "OverflowError: range() results has too many items"
Does anyone know how I can fix this?
Here is my code:
class Euler3:
"A class to find the largest prime factor of a given number"
n = 600851475143
primeFactors = []
for i in range(2,n):
if (n%i ==0):
primeFactors.append(i)
n = n/i
i = i -1 #reset i
print primeFactors
Any help or suggestions would be much appreciated!
The range function creates a list and tries to store it in memory. Creating a list many numbers long is what's causing the OverflowError. You can use xrange instead to get a generator which produces the numbers on demand.
That said, I think you'll find that your algorithm is way too slow for calculating large primes. There are a lot of prime number algorithms, but I might suggest checking out the Sieve of Eratosthenes as a starting point.
EDIT: Properly xrange actually doesn't return a generator, but an xrange object which behaves a lot like a generator. I'm not sure if you care, but it was bugging me that i wasn't precise!
I'm guessing you're using python 2 and not python 3 -- range(2,n) actually constructs a list! You don't have enough memory to store 600 billion numbers! xrange should be fine, though.
Also, your idea of i=i-1 doesn't work. For loops don't work like C, and that hack only works in C-style loops. The for loop iterates over range(2,n). If i gets the value 5 at once iteration, then no matter what you do to i, it still gets 6 the next time through.
Also, the list range(2,n) is constructed when you enter the loop. So when you modify n, that doesn't change anything.
You're going to have to rethink your logic a bit.
(if you don't believe me, try using 175 as a test case)
As a last comment, you should probably get in the habit of using the special integer division: n = n // i. Although / and // work the same in python 2, that is really deprecated behavior, and they don't work the same in python 3, where / will give you a floating point number.
You can fix the problem by using xrange instead of range
Your next problem will be that the program takes way too long to run because you need to break out of the loop under some condition
A better way to deal with repeat factors is to replace the if with a while
while (n%i ==0):
primeFactors.append(i)
n = n/i
n = 600851475143
primeFactors = []
for i in range(2,n):
i think you can optimize the function by noticing that
for i in range(2,n):
you can replace
range(2,n)
by
range(2,int(sqrt(n))+2)
because, you can see wiki...
This is the best way to find primes that I've found so far:
def isprime(n):
#make sure n is a positive integer
n = abs(int(n))
#0 and 1 are not primes
if n < 2:
return False
#2 is the only even prime number
if n == 2:
return True
#all other even numbers are not primes
if not n & 1:
return False
#range starts with 3 and only needs to go up to the square root of n
#for all odd numbers
for x in range (3, int(n**0.5)+1, 2):
if n % x == 0:
return False
return True #if it makes it through all the catches, it is a prime
This took me about 5 secs to get the answer.
import math
def is_prime_number(x):
for i in range(int(math.sqrt(x)), 2, -1):
if x % i == 0:
return False
return True
def next_prime_number(number):
#Returns the next prime number.
if number % 2 == 0 and number != 2:
number += 1
while not is_prime_number(number):
number += 2
return number
num = 600851475143
i = 2
while (i < long(math.sqrt(num) / 2)):
if num % i == 0:
largest = i
print largest
i = next_prime_number(i + 1)
xrange won't probably help you(or it may!),but the key thing here is to reliaze that you don't need to find the prime numbers up till 600851475143 or the factors of 600851475143,but it's prime factors,so...
Use the good old prime factorization method ,like so:
A=600851475143
n=2
fac=[]
while(n<=int(A)):
B=1
while(A%n==0):
B=0
A=A/n
if(B==0):
fac.append(n)
n=n+1
print max(fac)
This will return the argest prime factor almost instantly
I was battling with this Python "OverflowError", as well, working on this project. It was driving me nuts trying to come up with a combination that worked.
However, I did discover a clever, at least I think so :), way to do it.
Here is my code for this problem.
def IsNumberPrime(n):
bounds = int(math.sqrt(n))
for number in xrange(2,bounds+2):
if n % number == 0:
return False
return True
def GetListOfPrimeFactors(n):
primes = []
factors = GetListOfFactors(n)
if n % 2 == 0:
primes.append(2)
for entries in factors:
if IsNumberPrime(entries):
primes.append(entries)
return primes
GetListOfPrimeFactors(600851475143)
def GetListOfFactors(n):
factors = []
bounds = int(math.sqrt(n))
startNo = 2
while startNo <= bounds:
if n % startNo == 0:
factors.append(startNo)
startNo += 1
return factors
What I did was take the factors of the number entered and enter them into a list "factors". After that, I take the list of factors and determine which ones are primes and store them into a list, which is printed.
I hope this helps
-- Mike

Program to factorize a number into two smaller prime numbers

I have a very big number, and I want to make a program, that finds two prime numbers, that will give the original number, if multiplied.
Ex.
Original_number = 299
// The program should get these two numbers:
q = 13
p = 23
The program runs fine at the start, but at a certain point, it just stops, and I'm not sure what is wrong.
The code:
import time
import math
def main():
time1 = time.clock()
q = int(0)
p = int(0)
finalnumber = int(377)
print("in main \n")
print("q = ", q)
print("\n p = ", p)
gotResult = 0
while(gotResult == 0):
p = GetNextPrime(p)
if(p >= finalnumber):
q = GetNextPrime(q)
p = q
p = GetNextPrime(p)
if(q * p == finalnumber):
gotResult == 1
break
print("q = ", q)
print("\n p = ", p)
time2 = time.clock()
ElapsedTime = time2 - time1
print("Elapsed time: ", ElapsedTime)
def GetNextPrime(prime):
print("in GetNextPrime \n")
isPrime = 0
while(isPrime == 0):
prime = prime + 1
if(IsPrime(prime)== 1):
isPrime = 1
return prime
def IsPrime(prime):
print("in IsPrime \n")
isPrime = 0
i = 2
while(i <= math.sqrt(prime)):
if(i % 2 == 0):
i = i+1
if(prime % i == 0):
isPrime = 1
break
return isPrime
#start of program here
main()
I have written the program in python, and I know it probably isn't good, because I'm new to python.(I have been programming C++, and I'm not even good at it)
But I hope you can help me find the problem :)
ps. What is the maximum size of the original number? How many ciphers can it have?
Just factorize a number. You'll get a list of prime factors. If the list contains exactly two numbers, and the numbers are good for your purposes, you won. Else try another number.
But the approach above is quite wasteful. I'd rather take a list of primes, generate all pairs of it and multiply. The result would be a list of numbers that, well, can only be factorized into 2 primes. Like this:
some_primes = [2, 3, 5, 7, 11] # you can generate a better list
my_numbers = [x*y for x in some_primes for y in some_primes]
A simple approach is trial division:
import math
def factors(number):
return [(x, number / x) for x in range(int(math.sqrt(number)))[2:] if not number % x]
Then factors(299) returns [(13,23)]
There are problems with this method for large numbers:
Large numbers may exceed the python integer limit (found in sys.maxint). A 64-bit machine will be limited to 18 decimal digits.
Factoring large numbers is a hard problem, and an open research question. Trial division is about as brute force as it comes, but it will work for smaller numbers. Otherwise, you'll quickly need a more sophisticated algorithm. See wikipedia for a discussion.
If you're going to brute-force numerical problems, python is the wrong language. Identical algorithms will run faster in a compiled language like C++.
isPrime is wrong. You return 1 when the number is not prime. Also you never test if the number can be divided by 2. I didn't look any further than that.
Protip: Python is not C. There is True, False and you don't need all the brackets in if, while.
You should really test every function you write, not the whole program - that tells you nothing about where the bugs are.
In addition to Jochel Ritzel's and DSM's answers, the logic in main() while loop fails to account for cases when the number is not a product of two primes (then it will go into infinite loop).
Also, if you expect to factor really large numbers (say more than 20-30 digits), your approach is probably too slow. You should use Erastothenes sieve at minimum to generate a large enough list of primes in advance if you want to get acceptable results.
There are (pretty sophisticated) algoritms to deal with larger cases, but in general, this is a difficult problem and the solution to it scales very badly with number of digits.
In the following logic:
while(i <= math.sqrt(prime)):
if(i % 2 == 0):
i = i+1
if(prime % i == 0):
isPrime = 1
break
If i is odd and prime isn't divisible by it, it'll loop forever, and here it gets stuck on 3. [The other obvious problem has already been pointed out.]

Categories

Resources