33

I have been trying to write a program that will take an imputed number, and check and see if it is a prime number. The code that I have made so far works perfectly if the number is in fact a prime number. If the number is not a prime number it acts strange. I was wondering if anyone could tell me what the issue is with the code.

a=2
num=13
while num > a :
  if num%a==0 & a!=num:
    print('not prime')
    a=a+1
  else:
    print('prime')
    a=(num)+1

The result given when 24 is imputed is:

not prime
not prime
not prime
prime

How would I fix the error with the reporting prime on every odd and not prime for every even?

martineau
  • 119,623
  • 25
  • 170
  • 301
Chris
  • 401
  • 2
  • 7
  • 9
  • 5
    Your algorithm is deeply flawed. Try `15` – forivall Sep 16 '13 at 17:39
  • how do i fix that issue – Chris Sep 16 '13 at 17:52
  • 1
    (your previous comment was answered below) FYI: the standard, simple, efficient prime number checking algorithm is called the 'Sieve of Eratosthenes'. Look it up with your preferred search engine / croudsourced encyclopedia. – forivall Sep 16 '13 at 20:36
  • You can also try an Fermat's test for compositeness: https://en.wikipedia.org/wiki/Probable_prime def is_prime(x): return divmod(2 ** (x - 1), x)[1] == 1 – Vadim Zin4uk Nov 10 '15 at 19:42

14 Answers14

70

You need to stop iterating once you know a number isn't prime. Add a break once you find prime to exit the while loop.

Making only minimal changes to your code to make it work:

a=2
num=13
while num > a :
  if num%a==0 & a!=num:
    print('not prime')
    break
  i += 1
else: # loop not exited via break
  print('prime')

Your algorithm is equivalent to:

for a in range(a, num):
    if a % num == 0:
        print('not prime')
        break
else: # loop not exited via break
    print('prime')

If you throw it into a function you can dispense with break and for-else:

def is_prime(n):
    for i in range(3, n):
        if n % i == 0:
            return False
    return True

Even if you are going to brute-force for prime like this you only need to iterate up to the square root of n. Also, you can skip testing the even numbers after two.

With these suggestions:

import math
def is_prime(n):
    if n % 2 == 0 and n > 2: 
        return False
    for i in range(3, int(math.sqrt(n)) + 1, 2):
        if n % i == 0:
            return False
    return True

Note that this code does not properly handle 0, 1, and negative numbers.

We make this simpler by using all with a generator expression to replace the for-loop.

import math
def is_prime(n):
    if n % 2 == 0 and n > 2: 
        return False
    return all(n % i for i in range(3, int(math.sqrt(n)) + 1, 2))
Steven Rumbalski
  • 44,786
  • 9
  • 89
  • 119
  • 1
    This method is working, the only issue is when i put in 15 or 9, it says prime – Chris Sep 16 '13 at 17:33
  • 3
    You first example has no increment and will incorrectly report prime for every odd number and not prime for every even. Your third one uses `range(n)` which starts from 0, either 0 and 1 would hit the first condition and exit `False` for every number. – AChampion Sep 16 '13 at 17:35
  • 1
    How would i fix the error with the reporting prime on every odd and not prime for every even? – Chris Sep 16 '13 at 17:43
  • @achampion: Updated. Thanks for the corrections. – Steven Rumbalski Sep 16 '13 at 17:54
  • I would have edited this answer but the changes are too minor. The last line of this post should read: `return all(n % i for i in range(3, int(math.sqrt(n)) + 1, 2))`. There is a misplaced parenthesis. Otherwise there is a "SyntaxError: Generator expression must be parenthesized if not sole argument" error. – Fezter Mar 17 '14 at 04:07
  • Should I use range or xrange? I think xrange is more efficient but I'm very new to python. – Confuse Jun 28 '15 at 06:07
  • Do not use the last snippet. In the last snippet, the time complexity for n > 2 is O(N) while in the one before it, it's much less. – Arulx Z Nov 03 '15 at 09:09
  • @ArulxZ: You are incorrect about the time complexity of the last snippet differing from the other snippets. Perhaps you misunderstand that `all` shortcuts when the first false value is found. – Steven Rumbalski Nov 10 '15 at 20:50
  • Oh ok! I didn't know that. Thanks for clarification. – Arulx Z Nov 11 '15 at 05:18
  • 1
    I use the 3rd example and I get that 4 is Prime. Why is that? edit: I've change range(3, n): to range(2, n): , and is working now. thanks – Tosho Sep 25 '16 at 12:58
  • Isn't using `int(n**0.5)` better? – Confuse Mar 18 '18 at 05:00
24
def isprime(n):
    '''check if integer n is a prime'''

    # 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 
    # 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

Taken from:

http://www.daniweb.com/software-development/python/code/216880/check-if-a-number-is-a-prime-number-python

nbro
  • 15,395
  • 32
  • 113
  • 196
Destructor
  • 3,154
  • 7
  • 32
  • 51
  • 2
    +1 root square top limit – Alberto Megía Sep 16 '13 at 17:30
  • 3
    Copy/pasting from an external source (without any kind of curation) should be discouraged. Moreover, you're not discussing the OP's code. – forivall Sep 16 '13 at 17:39
  • Please don't copy/paste from exter sources and use it exactly as an answer, use links instead and add something of your own. – Tomarinator Sep 24 '14 at 17:22
  • I'm not sure Tomarinator's comment is right. The truth is it's links break and your recommended to not have the external link have the bulk of an answer. – Tatarize Feb 26 '21 at 06:02
14
def is_prime(n):
    return all(n%j for j in xrange(2, int(n**0.5)+1)) and n>1
Vinayak Kaniyarakkal
  • 1,110
  • 17
  • 23
  • This is far from being the optimal algorithm. For example, you are checking also even numbers, but clearly, except 2, primes are odd numbers. – nbro Jan 19 '16 at 14:00
  • 2
    You can make this far more optimal by removing the square brackets to stop iterating after you know it's not prime. Moreover, please don't shorten algorithms like this :P If you want short then just do `all(n%j for j in range(2,n))*(n>1)` :P – hyper-neutrino Sep 08 '17 at 19:27
10

The two main problems with your code are:

  1. After designating a number not prime, you continue to check the rest of the divisors even though you already know it is not prime, which can lead to it printing "prime" after printing "not prime". Hint: use the `break' statement.
  2. You designate a number prime before you have checked all the divisors you need to check, because you are printing "prime" inside the loop. So you get "prime" multiple times, once for each divisor that doesn't go evenly into the number being tested. Hint: use an else clause with the loop to print "prime" only if the loop exits without breaking.

A couple pretty significant inefficiencies:

  1. You should keep track of the numbers you have already found that are prime and only divide by those. Why divide by 4 when you have already divided by 2? If a number is divisible by 4 it is also divisible by 2, so you would have already caught it and there is no need to divide by 4.
  2. You need only to test up to the square root of the number being tested because any factor larger than that would need to be multiplied with a number smaller than that, and that would already have been tested by the time you get to the larger one.
kindall
  • 178,883
  • 35
  • 278
  • 309
3

This example is use reduce(), but slow it:

def makepnl(pnl, n):
    for p in pnl:
        if n % p == 0:
            return pnl
    pnl.append(n)
    return pnl

def isprime(n):
    return True if n == reduce(makepnl, range(3, n + 1, 2), [2])[-1] else False

for i in range(20):
    print i, isprime(i)

It use Sieve Of Atkin, faster than above:

def atkin(limit):
    if limit > 2:
        yield 2
    if limit > 3:
        yield 3

    import math
    is_prime = [False] * (limit + 1)

    for x in range(1,int(math.sqrt(limit))+1):
        for y in range(1,int(math.sqrt(limit))+1):
            n = 4*x**2 + y**2

            if n<=limit and (n%12==1 or n%12==5):
                # print "1st if"                                                                                                                    
                is_prime[n] = not is_prime[n]
            n = 3*x**2+y**2
            if n<= limit and n%12==7:
                # print "Second if"                                                                                                                 
                is_prime[n] = not is_prime[n]
            n = 3*x**2 - y**2
            if x>y and n<=limit and n%12==11:
                # print "third if"                                                                                                                  
                is_prime[n] = not is_prime[n]

    for n in range(5,int(math.sqrt(limit))):
        if is_prime[n]:
            for k in range(n**2,limit+1,n**2):
                is_prime[k] = False

    for n in range(5,limit):
        if is_prime[n]: yield n

def isprime(n):
    r = list(atkin(n+1))
    if not r: return False
    return True if n == r[-1] else False

for i in range(20):
    print i, isprime(i)
Community
  • 1
  • 1
Keisuke URAGO
  • 89
  • 2
  • 6
2

Your problem is that the loop continues to run even thought you've "made up your mind" already. You should add the line break after a=a+1

Ofir Israel
  • 3,785
  • 2
  • 15
  • 13
1

After you determine that a number is composite (not prime), your work is done. You can exit the loop with break.

while num > a :
  if num%a==0 & a!=num:
    print('not prime')
    break          # not going to update a, going to quit instead
  else:
    print('prime')
    a=(num)+1

Also, you might try and become more familiar with some constructs in Python. Your loop can be shortened to a one-liner that still reads well in my opinion.

any(num % a == 0 for a in range(2, num))
Prashant Kumar
  • 20,069
  • 14
  • 47
  • 63
1

Begginer here, so please let me know if I am way of, but I'd do it like this:

def prime(n):
    count = 0
    for i in range(1, (n+1)): 
         if n % i == 0: 
             count += 1
    if count > 2:
        print "Not a prime"
    else:
        print "A prime"
dasdachs
  • 709
  • 10
  • 18
0

This would do the job:

number=int(raw_input("Enter a number to see if its prime:"))
if number <= 1:
    print "number is not prime"
else:
    a=2
    check = True
    while a != number:
        if number%a == 0:
            print "Number is not prime"
            check = False
            break
        a+=1
    if check == True:
        print "Number is prime" 
0
a=input("Enter number:")

def isprime(): 

    total=0
    factors=(1,a)# The only factors of a number
    pfactors=range(1,a+1) #considering all possible factors


    if a==1 or a==0:# One and Zero are not prime numbers
        print "%d is NOT prime"%a


    elif a==2: # Two is the only even prime number
        print "%d is  prime"%a


    elif a%2==0:#Any even number is not prime except two
        print "%d is NOT prime"%a  



    else:#a number is prime if its multiples are 1 and itself 
         #The sum of the number that return zero moduli should be equal to the "only" factors
        for number in pfactors: 
            if (a%number)==0: 
                total+=number
        if total!=sum(factors):
            print "%d is NOT prime"%a 
        else:
             print "%d is  prime"%a
isprime()
Mansueli
  • 6,223
  • 8
  • 33
  • 57
0

This is a slight variation in that it keeps track of the factors.

def prime(a):
    list=[]
    x=2
    b=True

    while x<a:
        if a%x==0:
            b=False
            list.append(x)
        x+=1

    if b==False:
        print "Not Prime"
        print list
    else:
        print "Prime"
saegarde
  • 9
  • 3
0

Prime number check.

def is_prime(x):
    if x < 2:
        return False
    else:
        if x == 2:
            return True
        else:
            for i in range(2, x):
                if x % i == 0:
                    return False
            return True
x = int(raw_input("enter a prime number"))
print is_prime(x)
KillianDS
  • 16,936
  • 4
  • 61
  • 70
0
max=int(input("Find primes upto what numbers?"))
primeList=[]
for x in range(2,max+1):
    isPrime=True
    for y in range(2,int(x**0.5)+1) :
        if x%y==0:
            isPrime=False
            break

    if isPrime:
        primeList.append(x)
print(primeList)
  • 1
    Can you edit your answer, and provide some explanation with your code to help OP understand? Thanks – Paco Feb 02 '15 at 16:50
0

# is digit prime? we will see (Coder: Chikak)

def is_prime(x): flag = False if x < 2: return False else: for count in range(2, x): if x % count == 0: flag = True break if flag == True: return False return True

Rao
  • 20,781
  • 11
  • 57
  • 77
Chikak
  • 29
  • 1