Image of the glider from the Game of Life by John Conway
Skip to content

Prime Numbers In Python

The following program returns True if a number is prime or False otherwise. I am proud of this code, as it implements dead code. Upon the first positive condition in the if statement nested in the while loop, the program terminates, ignoring any further code following. As far as I can tell, this is the most efficient way (not necessarily the fastest) to test if a number is prime or not. This means that this function has an order of O(n-2) (it doesn't test against 1 and itself) as a worst case scenario, and O(n/m) where m is the first factor of n as a best case. As elementary as it is, I think it's pretty slick. All handled in 9 very readable lines of code.

UPDATE: Thanks to some observant readers, I have come to the realization that I only need to loop to the square root of n, and not n, as the square root of n is the largest factor. This brings the order to O(sqrt(n)-2) at the worst case scenario, and O(1) as the best case.

1
2
3
4
5
6
7
8
9
def is_prime(n):
    import math
    n = abs(n)
    i = 2
    while i <= math.sqrt(n):
        if n % i == 0:
            return False
        i += 1
    return True

{ 30 } Comments

  1. rbu using Firefox 2.0.0.6 on GNU/Linux 64 bits | September 5, 2007 at 3:17 pm | Permalink

    One simple optimization: The while loop can stop when i > sqrt(n). If no factors were found until then, there won't be any in (sqrt(n),n].
    Other optimizations include not testing every single number as divisor, but only new prime numbers. Check the Sieve of Eratosthenes for details.

    --rbu

  2. Swistak using Firefox 2.0.0.6 on Ubuntu | September 5, 2007 at 3:30 pm | Permalink

    There are A LOT faster algorithms doing that job. They make use of number theory and work in polynomial time (in terms of number length)

  3. Rocco Stanzione using Firefox 2.0.0.6 on Ubuntu 64 bits | September 5, 2007 at 4:07 pm | Permalink

    Good stuff! I rubified it and started playing with it, and sped it up thusly (don't forget to change the &lt; back to a <, your software hates it):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Integer
      def is_prime?
        i=3
        return false if self % 2 == 0 and self != 2
        while i &lt; self/2
          return false if self % i == 0
          i += 2
        end
        return true
      end
    end
  4. Rocco Stanzione using Firefox 2.0.0.6 on Ubuntu 64 bits | September 5, 2007 at 4:12 pm | Permalink

    Also rbu is right, doing while i <= sqrt(n) (or sqrt(self) in my ruby) it's very much faster.

  5. Pansen using Firefox 2.0.0.6 on Ubuntu | September 5, 2007 at 4:16 pm | Permalink

    what are you talking about? this is very trivial code that is not even remotely efficient at what it's supposed to do.

  6. randomwalker using Firefox 2.0.0.6 on Ubuntu | September 5, 2007 at 4:47 pm | Permalink

    Seriously, WTF? This is the opposite of slick.

  7. Rocco Stanzione using Firefox 2.0.0.6 on Ubuntu 64 bits | September 5, 2007 at 4:53 pm | Permalink

    Last post I promise! Sure there are plenty of faster algorithms. But this is reasonably fast, reasonably efficient and accomplished with reasonably little code. It's also very useful for both testing primeness and enumerating primes. Anyway I made it faster still and more accurate (1 is not a prime number). This enumerated all the primes from 1 to 1M in 34 seconds for me:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Integer
      def is_prime?
        i=3
        return false if self % 2 == 0 and self != 2
        ss = sqrt(self).floor
        return false if ss**2 == self
        while i &lt;= ss
          return false if self % i == 0
          i += 2
        end
        return true
      end
    end
  8. Aaron using Debian IceWeasel 2.0.0.6 on Debian GNU/Linux 64 bits | September 5, 2007 at 5:16 pm | Permalink

    @rbu- Ahh, good call. Makes perfect sense.

    @Swistak- As I mentioned in the post, there are probably faster algorithms.

    @Rocco Stanzione- No problem. Keep posting. :) Thanks for the code, by the way.

    @Pansen & randomwalker- Thanks for the informative comments. Very well thought through.

  9. Xyhthyx using Firefox 2.0.0.6 on Ubuntu | September 5, 2007 at 7:20 pm | Permalink

    Perl version anyone?

    sub is_prime {
    my ($n) = @_;
    $n = abs($n);
    my i = 2;
    while ($i

  10. Charles McCreary using Firefox 2.0.0.5 on Ubuntu | September 5, 2007 at 8:26 pm | Permalink

    Your post got me thinking about python and optimizations. So I googled about and found a few algorithms that are pretty fast at determining primeness. I posted them here: http://www.tiawichiresearch.com/?m=200709

  11. Jon using Firefox 2.0.0.6 on Ubuntu | September 5, 2007 at 8:57 pm | Permalink

    C++ version, anyone?

    1
    2
    3
    4
    5
    6
    7
    8
    bool isPrime(long p)
    {
      long maxfactor = static_cast(sqrt(p) + 1);        // round up
      for (long n = 2; n &lt; maxfactor; ++n)
        if (p % n == 0)
          return false;
      return true;
    }

    Just for reference, to test each number in [1, 10^6], the C/C++ version is a bit more than an order of magnitude faster than the sqrt-optimized version of the above python; python (2.10 sec versus 39.5 sec).

    Programming posts are always nice to see in my reader; keep up the learning!

    (Side note: I can't put a less-than sign in my comment. It appears that the post page thinks its a tag start, so I tried < but that shows literally, as seen above.)

  12. anon using Firefox 2.0.0.6 on Ubuntu | September 5, 2007 at 10:01 pm | Permalink

    You may find this interesting:

    http://www.math.princeton.edu/~annals/issues/2004/Sept2004/Agrawal.pdf

  13. anon using Firefox 2.0.0.6 on Ubuntu | September 5, 2007 at 10:06 pm | Permalink

    In 2004, Agrawal, Kayal, and Saxena published this paper:
    http://www.math.princeton.edu/~annals/issues/2004/Sept2004/Agrawal.pdf
    in which they present a polynomial time algorithm to determine if a number is prime or composite.

    Note that it is a polynomial time algorithm in the size of the input.

    I hope you find that article interesting. In addition to proving a deep result, the references section will point you to just about everything you could care to know about primes.

  14. Walther using Firefox 2.0.0.6 on Ubuntu | September 5, 2007 at 10:59 pm | Permalink

    Hehe, as usual I got carried away and programmed multiple versions myself in Python (including a sieve algorithm and a caching version of your algorithm).
    For the critics here: the simple algorithm (with the sqrt) is pretty fast at least up until (2^31)-1.
    If you want to be fast for big primes, you would probably pick a different language anyway.

  15. Karl Lattimer using Firefox 2.0.0.6 on Ubuntu | September 6, 2007 at 2:17 am | Permalink

    Careful of sweeping statements like "As far as I can tell, this is the most efficient way (not necessarily the fastest) to test if a number is prime or not."

    When its hardly efficient, or elegant, and efficiency in software implies speed.

    If I were to ask you whether or not 578438089702734102192371840427834912121157 were prime or not how long would it take to identify that? PGP has been implementing prime testing and deriving primes in far more efficient ways for a long time, and can determine whether or not a 4096bit number is prime in a few seconds.

    Exploit sieves and "don't care" cases faster.

  16. Cornelius DuLac using Firefox 2.0.0.6 on Ubuntu | September 6, 2007 at 6:03 am | Permalink

    I don't think you are using the O notation correctly. Using binary search to search through a list of n ordered numbers takes O(sqrt(n)). Here, n is not the number of inputs, it's the input itself.

    Now, if you were saying n was the size of the input number, I think you'll find that your notation is still flawed. This is not a poly time algorithm. If it were, you would be able to break several encryption algorithms that rely on the hardness of the primality problem, as well (I believe) P=NP.

    It's been a while since I've done algorithmics in school, but I think you'll find I am right.

    C.

  17. Levi using Firefox 2.0.0.6 on Windows XP | September 6, 2007 at 11:59 am | Permalink

    A couple of comments regarding the complexity of this algorithm.

    First, you don't include lower-order factors in big-O notation. An algorithm that takes n-1 steps is still O(n). An algorithm that takes n^2+5n+2 steps is O(n^2), or simply Polynomial Time when speaking in terms of complexity classes.

    Second, you're ignoring the fact that, for large numbers, modulo is not a constant time operation. The O(sqrt(n)) complexity is only correct if n is the size of your number and it fits in the hardware. This isn't true in general, so it's not very useful for the sorts of reasoning big-O notation was invented for.

    To be general, you need to define the algorithm in terms of the number of bits in your input number. For an integer N, it takes log N + 1 bits to store it. That means that the complexity in terms of the input size is O(2^(n/2)). This is exponential, i.e. very bad. A 1024 bit integer gives you a running time of essentially 2^512, which is definitely intractable.

    As other people have stated, there are much better algorithms for primality testing, and the one you're using is worthless for crypto applications.

    My reference for this comment: Complexity and Cryptography: An Introduction

  18. Aaron using Debian IceWeasel 2.0.0.6 on Debian GNU/Linux 64 bits | September 6, 2007 at 12:41 pm | Permalink

    @Levi- Fair enough. My inexperience really shows through on things like this. I need to spend more time on math-related algorithms analyzing their complexity and what's going on under the hood I think.

    Again, thanks for the info.

  19. Francesc Dorca using Firefox 2.0.0.6 on Ubuntu | September 6, 2007 at 2:39 pm | Permalink

    Hi Aaron,

    First of all congratulations for your interesting blog.

    Let me suggest an improvement to make your code much more efficient.

    I do not know Python, but using my knowledge on other programming languages I think that I can understand your code pretty well.

    You can use only integer arithmetic doing two minor changes.

    Eliminate the sentence

    1
    import math

    and replace the line

    1
    while i &lt;= math.sqrt(n):

    by the equivalent sentence

    1
    while i*i &lt;= n:

    that uses only integer arithmetics.

  20. Johnathan Nguyen using Firefox 2.0.0.11 on Windows XP | December 27, 2007 at 5:10 pm | Permalink

    Review this publication: Prime Sequence Homology by Daniel Blake et al; Fourrier University, Grenoble

    Dr. Blake's approach is via a randomization channel. Code is also presented. I tried to cut and paste but was unsuccessful.

  21. lizz using Firefox 3.0 on Windows XP | June 23, 2008 at 5:29 am | Permalink

    your story is sux, try to test, for example, 99999999977 or 4740914805200312594461
    try to read about miller-tabin algorythm

    P.S. sorry for my english ;)

  22. Veerabhadra Rao using Firefox 3.0.14 on Ubuntu | April 1, 2010 at 7:29 am | Permalink

    how are you

  23. Veerabhadra Rao using Firefox 3.0.14 on Ubuntu | April 1, 2010 at 7:46 am | Permalink

    iam a iiit student in nuzvid from visakhapatnam

  24. kotireddy using Firefox 3.0.14 on Ubuntu | April 8, 2010 at 11:28 pm | Permalink

    def isPrimenumber(number):
    c=0
    for i in range(number):
    if number%(i+1)==0:
    c=c+1
    if c>2:
    print number,"is not prime number"
    else:
    print number,"is prime number"
    num=raw_input("enter a number:")
    num=int(num)
    isPrimenumber(num)

  25. people using Google Chrome 5.0.307.11 on GNU/Linux | June 14, 2010 at 9:28 am | Permalink

    n=input("Enter any number-")
    if n==2:
    print "prime"
    if n==1:
    print "neither prime nor composite"
    if n>2:
    for i in range(2,n):
    if n%i==0:
    print "composite"
    break
    i=i+1
    else:
    print "prime"
    else:
    print "enter correct input"

  26. nolfonzo using Firefox 3.6.8 on Windows XP | September 3, 2010 at 12:51 pm | Permalink

    Using Numpy and a sieve a approach you can generate these very fast. I wrote about this on my blog recently: http://rebrained.com/?p=458

    import math
    import numpy
    def prime6(upto):
    primes=numpy.arange(3,upto+1,2)
    isprime=numpy.ones((upto-1)/2,dtype=bool)
    for factor in primes[:int(math.sqrt(upto))]:
    if isprime[(factor-2)/2]: isprime[(factor*3-2)/2:(upto-1)/2:factor]=0
    return numpy.insert(primes[isprime],0,2)

  27. Bismoy using Google Chrome 5.0.375.127 on Windows 7 | September 5, 2010 at 12:21 pm | Permalink

    gr8 stuff...........

  28. Tom Jones using Google Chrome 8.0.552.231 on Mac OS | December 18, 2010 at 5:38 pm | Permalink

    A for loop is even cleaner

    from math import sqrt

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

  29. sanjo using Google Chrome 10.0.648.133 on GNU/Linux | March 17, 2011 at 8:25 pm | Permalink

    Nice one, thank you. :)

  30. nolfonzo using Google Chrome 10.0.648.204 on Mac OS | April 10, 2011 at 5:26 pm | Permalink

    Tom I think you may need sqrt(n)+1

Post a Comment

Your email is never published nor shared.

Switch to our mobile site