Primality test in python [duplicate] - python

This question already has answers here:
How to create the most compact mapping n → isprime(n) up to a limit N?
(29 answers)
Closed 7 years ago.
I'm trying to do a simple primality test in Python.
Accoding to Wikipedia, a primality test is the following:
Given an input number n, check whether any integer m from 2 to n − 1 divides n. If n is divisible by any m then n is composite, otherwise it is prime.
I started with ruling out the even numbers - with the exception of 2 - as candidates to prime
def prime_candidates(x):
odd = range(1, x, 2)
odd.insert(0, 2)
odd.remove(1)
return odd
Then writing a function to check for primes, according to the rules above.
def isprime(x):
for i in range(2, x-1):
if x % i == 0:
return False
else:
return True
And this is the main function, which iterates over a list of 8000 prime candidates and tests their primality
def main():
end = 8000
candidates = prime_candidates(end)
for i in candidates:
if isprime(i) and i < end:
print 'prime found ' + str(i)
The problem is that the isprime function returns True for numbers that aren't primes.

Have a look at the Miller–Rabin primality test if a probabilistic algorithm will suffice. You could also prove a number to be prime, with for instance Elliptic Curve Primality Proving (ECPP), but it takes more effort.
A simple trial division algorithm is the following
def prime(a):
return not (a < 2 or any(a % x == 0 for x in range(2, int(a ** 0.5) + 1)))
Edit:
Here's a more educational version because the first solution is very condensed and perhaps harder to read:
from math import sqrt
def prime(a):
if a < 2: return False
for x in range(2, int(sqrt(a)) + 1):
if a % x == 0:
return False
return True
I've substituted in sqrt(a) in place of a ** 0.5 to make things more clear. The square root is used to not look at more factors than we have to.

In brief, your isprime(x) checks whether the number is odd, exiting right after if x % 2 == 0.
Try a small change so that you would actually iterate:
def isprime(x):
for i in range(2, x-1):
if x % i == 0:
return False
else:
return True
Note that else: is now part of the for loop rather than if statement.

Your function actually returns whether your number is odd.
Indeed, what you're doing is you're checking whether 2 divides your number, and return immediately. You never check for the other numbers.
What you need to do is take this return true out of the if's else clause and the for loop back into the main function body.
On a sidenote, If you're looking for the primes lower than a given number, you could store the primes you found in memory and then only try dividing you new number by those primes !
(because if d is composite and divides q, then p exists such that p is prime and p divides q).

The problem is that you put return False in the else clause rather than at the end of the function. So your function will return right after the first divisor is checked, rather than going on to check other divisors.
Here is a simple primality test similar to yours:
def is_prime(n):
d = 2
while d * d <= n:
if n % d == 0:
return False
d += 1
return n > 1

Related

check if integer is a prime, if not return smallest factor [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I need to check if the given integer is a prime, and return True if so. If not, I need to find the smallest factor which is more than 1. I'm completely new to this and even though code compiles it fails several test cases.
def isPrime(n):
if (n <= 1) :
return n
if (n <= 3) :
return 1
if (n % 2 == 0 or n % 3 == 0) :
return 2
i = 5
while(i * i <= n) :
if (n % i == 0 or n % (i + 2) == 0) :
return i
i = i + 6
return True
A prime is a number that can only be divided by one and itself. So, if we test x, we should test every number y such that 1 < y < x. A good way to test this is to use a for loop. Here is an example:
def isPrime(n):
for i in range(2,n):
if n % i == 0:
return False # because that means that something divides into n perfectly
return True
There are a few problems with this:
isPrime(1) returns True
Any negative number will return True
The program gets quite a bit slower as the numbers get bigger. For example, it takes 0.145 seconds to complete isPrime(1000003), but primes take longer to process, because as soon as a factor is found, the entire function stops and returns, whereas for a prime to be found, it has to run through every iteration up to n.
I'll leave those problems to you for the moment. In the meantime, we need a way to return the smallest factor. This is actually very easily done:
def isPrime(n):
for i in range(2,n):
if n % i == 0:
return i # i at this iteration is equal to the smallest factor
return True
So isPrime(20) returns 2, and isPrime(19) returns True. Hopefully this satisfies your needs.

Is my code correct for an issue involving prime number tracking and consecutive addition?

The question: Assume the availability of a function is_prime. Assume a variable n has been associated with positive integer. Write the statements needed to find out how many prime numbers (starting with 2 and going in increasing order with successively higher primes [2,3,5,7,11,13,...]) can be added before exceeding n. Associate this number with the variable k.
The code:
def is_prime():
i = 2
k = 0
Again = True
while Again = True:
if total > n:
Again = False
for x in range(2,n):
if x % i == 0:
total = total
k = k
i += 1
else:
total += x
k += 1
return k
Your code is not correct for an issue involving prime number tracking and consecutive addition. Nor anything else. The obvious issue is that it doesn't run, so it can't be correct. One syntax bug is this:
while Again = True:
which should be:
while Again == True:
Another is that total is never initialized before it's value is used:
total += x
Once we fix those problems, your code still doesn't appear to work. But let's back up a bit. The stated problem says,
Assume the availability of a function is_prime.
But you didn't do that -- you wrote your solution with the name is_prime(). We should expect that there is a function named is_prime(n) and it tests if n is prime or not, returning True or False. You are either given this, need to find one, write one, or simply assume it exists but never actually test your code. But once you have this function, and it works, you shouldn't change it!
Here's my example is_prime(n) function:
def is_prime(n):
""" Assume the availability of a function is_prime. """
if n < 2:
return False
if n % 2 == 0:
return n == 2
for m in range(3, int(n ** 0.5) + 1, 2):
if n % m == 0:
return False
return True
Now write your solution calling this function, but not changing this function. Here's one possible algorithm:
Write a function called primes_in_sum(n)
Set the variable prime to 2 and the variable k (our counter) to
0.
Subtract prime from n.
While n >= 0, increment k, and compute the next value of prime
by keep adding one to prime until is_prime(prime) returns true.
Then again subtract prime from n. Back to the top of this loop.
When the while condition fails, return k.
Test your code works by outputting some values:
for n in range(2, 100):
# Assume a variable n has been associated with a positive integer
print(n, primes_in_sum(n))
Check in your head that the results are reasonable.

While loops with multiple condtions. Python

I'm writing a function that, given a random int, will return the next int that is both a prime number and a palindrome. i.e getint(13) will return 101.
One of the conditions of this function is that recursion is not allowed.
Where am i going wrong here?
def golf(number):
x = number +1
for i in range(2, x):
while str(x) != str(x)[::-1] and x % i == 0:
x += 1
return x
Divide the problem into smaller pieces. It will be easier for you to understand what's going on:
def golf(number):
x = number + 1
while True:
if is_palindrome(x) and is_prime(x):
return x
x += 1
Now all you have to do is implement is_palindrome(x) and is_prime(x):
import math
def is_prime(x):
for i in xrange(2, math.ceil(math.sqrt(x))+1):
if x % i == 0:
return False
return True
def is_palindrome(x):
x = str(x)
return x == x[::-1]
Side note: the math.ceil(math.sqrt(x))+1 might be an overkill (perhaps int(...)+1 is enough) if math.sqrt works correctly for squares (i.e. does not depend on floating point calculations so math.sqrt(a*a)==a is always true). Well in worst case the loop will do one more iteration then necessary. Better safe then sorry.
Your for loop will only go as far as x's initial value: the range(2,x) is computed only once, right after x = number + 1. So increasing x inside the loop doesn't make a difference. Consider using a while loop, something like:
i = 2
while i <= x:
...
i += 1
And you should probably first check is x is a palindrome (a "cheap" operation) and then, if it is, check weather it is prime (an "expensive" operation), not try do it all in a couple of nested loops that make little sense.
In your code:
def golf(number):
x = number +1
for i in range(2, x):
while str(x) != str(x)[::-1] and x % i == 0:
x += 1
return x
The program execution will not satisfy the while loop half of the time since any even number will not be divisible by any odd number and vice-versa. Also in a single iteration of the for loop, x will be incremented every time the while loop is satisfied.
You need to separate the prime checking and palindrome checking. The approach given by freakish is the simplest.

Finding all divisors of a number optimization

I have written the following function which finds all divisors of a given natural number and returns them as a list:
def FindAllDivisors(x):
divList = []
y = 1
while y <= math.sqrt(x):
if x % y == 0:
divList.append(y)
divList.append(int(x / y))
y += 1
return divList
It works really well with the exception that it's really slow when the input is say an 18-digit number. Do you have any suggestions for how I can speed it up?
Update:
I have the following method to check for primality based on Fermat's Little Theorem:
def CheckIfProbablyPrime(x):
return (2 << x - 2) % x == 1
This method is really efficient when checking a single number, however I'm not sure whether I should be using it to compile all primes up to a certain boundary.
You can find all the divisors of a number by calculating the prime factorization. Each divisor has to be a combination of the primes in the factorization.
If you have a list of primes, this is a simple way to get the factorization:
def factorize(n, primes):
factors = []
for p in primes:
if p*p > n: break
i = 0
while n % p == 0:
n //= p
i+=1
if i > 0:
factors.append((p, i));
if n > 1: factors.append((n, 1))
return factors
This is called trial division. There are much more efficient methods to do this. See here for an overview.
Calculating the divisors is now pretty easy:
def divisors(factors):
div = [1]
for (p, r) in factors:
div = [d * p**e for d in div for e in range(r + 1)]
return div
The efficiency of calculating all the divisors depends on the algorithm to find the prime numbers (small overview here) and on the factorization algorithm. The latter is always slow for very large numbers and there's not much you can do about that.
I'd suggest storing the result of math.sqrt(x) in a separate variable, then checking y against it. Otherwise it will be re-calculated at each step of while, and math.sqrt is definitely not a light-weight operation.
I would do a prime factor decomposition, and then compute all divisors from that result.
I don't know if there's much of a performance hit, but I'm pretty sure that cast to an int is unnecessary. At least in Python 2.7, int x / int y returns an int.

Optimization of prime number code

This is my code in python for calculation of sum of prime numbers less than a given number.
What more can I do to optimize it?
import math
primes = [2,] #primes store the prime numbers
for i in xrange(3,20000,2): #i is the test number
x = math.sqrt(i)
isprime = True
for j in primes: #j is the devider. only primes are used as deviders
if j <= x:
if i%j == 0:
isprime = False
break
if isprime:
primes.append(i,)
print sum (primes,)
You can use a different algorithm called the Sieve of Eratosthenes which will be faster but take more memory. Keep an array of flags, signifying whether each number is a prime or not, and for each new prime set it to zero for all multiples of that prime.
N = 10000
# initialize an array of flags
is_prime = [1 for num in xrange(N)]
is_prime[0] = 0 # this is because indexing starts at zero
is_prime[1] = 0 # one is not a prime, but don't mark all of its multiples!
def set_prime(num):
"num is a prime; set all of its multiples in is_prime to zero"
for x in xrange(num*2, N, num):
is_prime[x] = 0
# iterate over all integers up to N and update the is_prime array accordingly
for num in xrange(N):
if is_prime[num] == 1:
set_prime(num)
primes = [num for num in xrange(N) if is_prime[num]]
You can actually do this for pretty large N if you use an efficient bit array, such as in this example (scroll down on the page and you'll find a Sieve of Eratosthenes example).
Another thing you could optimize is move the sqrt computation outside the inner loop. After all, i stays constant through it, so there's no need to recompute sqrt(i) every time.
primes = primes + (i,) is very expensive. It copies every element on every pass of the loop, converting your elegant dynamic programming solution into an O(N2) algorithm. Use lists instead:
primes = [2]
...
primes.append(i)
Also, exit the loop early after passing sqrt(i). And, since you are guaranteed to pass sqrt(i) before running off the end of the list of primes, update the list in-place rather than storing isprime for later consumption:
...
if j > math.sqrt(i):
primes.append(i)
break
if i%j == 0:
break
...
Finally, though this has nothing to do with performance, it is more Pythonic to use range instead of while:
for i in range(3, 10000, 2):
...
Just another code without using any imports:
#This will check n, if it is prime, it will return n, if not, it will return 0
def get_primes(n):
if n < 2:
return 0
i = 2
while True:
if i * i > n:
return n
if n % i == 0:
return 0
i += 1
#this will sum up every prime number up to n
def sum_primes(n):
if n < 2:
return 0
i, s = 2, 0
while i < n:
s += get_primes(i)
i += 1
return s
n = 1000000
print sum_primes(n)
EDIT: removed some silliness while under influence
All brute-force type algorithms for finding prime numbers, no matter how efficient, will become drastically expensive as the upper bound increases. A heuristic approach to testing for primeness can actually save a lot of computation. Established divisibility rules can eliminate most non-primes "at-a-glance".

Categories