3

I'm trying to get a fast way to determine if a number is prime using Python.

I have two functions to do this. Both return either True or False.

Function isPrime1 is very fast to return False is a number is not a prime. For example with a big number. But it is slow in testing True for big prime numbers.

Function isPrime2 is faster in returning True for prime numbers. But if a number is big and it is not prime, it takes too long to return a value. First function works better with that.

How can I come up with a solution that could quickly return False for a big number that is not prime and would work fast with a big number that is prime?

def isPrime1(number): #Works well with big numbers that are not prime
    state = True
    if number <= 0:
        state = False
        return state
    else:          
        for i in range(2,number):
            if number % i == 0:
                state = False
                break
        return state

def isPrime2(number): #Works well with big numbers that are prime   
    d = 2
    while d*d <= number:
        while (number % d) == 0:            
            number //= d
        d += 1
    if number > 1:       
        return True
    else:
        return False`
martineau
  • 119,623
  • 25
  • 170
  • 301
numersoz
  • 77
  • 1
  • 1
  • 8
  • https://en.wikipedia.org/wiki/Primality_test – Ry- Oct 20 '17 at 03:26
  • 3
    Use a Bloom filter that is pre-initialized with a list of prime numbers up to the largest you need to consider. – Mark Ransom Oct 20 '17 at 03:27
  • http://compoasso.free.fr/primelistweb/page/prime/accueil_en.php – alvas Oct 20 '17 at 03:42
  • 2
    How big ? Please be very specific, because the answer will directly depend on that. –  Oct 20 '17 at 06:43
  • Your first version continues trying all divisors past the square root of `n`, plus uses a huge `range`. It must be banned forever ! Also, trying all even divisors is a pity ! –  Oct 20 '17 at 07:11
  • There are many posts on this site about fast primality testing in Python. Did you look through them, and why do they not meet your needs? – Rory Daulton Oct 20 '17 at 09:54
  • 2
    @RoryDaulton: Not sure that's a good duplicate. Primality testing is an easier problem than full-blown factorization. – Mark Dickinson Oct 20 '17 at 11:05
  • 1
    Still the wrong duplicate. Prime factorization and primality testing are not the same thing. Checking whether a 1000-digit number is (probably) prime is trivially quick; doing a determistic primality check for such a number is slower, but still feasible. But that's way out of the range of effective factorization. – Mark Dickinson Oct 20 '17 at 15:00
  • Sympy: https://docs.sympy.org/latest/modules/ntheory.html#sympy.ntheory.primetest.isprime – Rexcirus Jul 03 '22 at 15:35

3 Answers3

12

Exhaustive division until the square root is about the simplest you can think of. Its worst case is for primes, as all divisions must be performed. Anyway, until a billion, there is virtually no measurable time (about 1.2 ms for 1000000007).

def FirstPrimeFactor(n):
    if n & 1 == 0:
        return 2
    d= 3
    while d * d <= n:
        if n % d == 0:
            return d
        d= d + 2
    return n

Note that this version returns the smallest divisor rather than a boolean.

Some micro-optimizations are possible (such as using a table of increments), but I don' think they can yield large gains.

There are much more sophisticated and faster methods available, but I am not sure they are worth the fuss for such small n.

  • @KellyBundy: rename it FirstPrimeFactor. Good day to you as well. –  Nov 18 '22 at 08:01
  • Ok, better. Still somewhat inconvenient and error-prone having to add extra logic outside for an actual primality check. One might think `FirstPrimeFactor(n) == n` does it, but that makes `1` look prime. Actually, `FirstPrimeFactor(1)` returning `1` is already not good, as 1 is just not a prime factor. I think `None` would be the proper result there, although that's also inconvenient for the caller to handle. I guess `2 <= n == FirstPrimeFactor(n)` is the right way to use this, might be good to state that. – Kelly Bundy Nov 18 '22 at 18:30
  • @KellyBundy: please investigate the case of n == 0 and n < 0. –  Nov 18 '22 at 19:22
  • I already had. What about them? Not supporting negative numbers is reasonable, and returning 2 for n=0 is reasonable as well. – Kelly Bundy Nov 18 '22 at 19:49
  • @KellyBundy: mh, this invalidates the well known property a ≤ a.b for natural b. Should I delete my answer ? –  Nov 18 '22 at 20:25
1

Primality tests is a very tricky topic.

Before attempting to speed up your code, try to make sure it works as intended. I suggest you start out with very simple algorithms, then build from there.

Of interest, isPrime2 is flawed. It returns True for 6, 10, 12, ...

lines 3 to 6 are very telling

while d*d <= number:
    while (number % d) == 0:            
        number //= d
    d += 1

When a factor of number d is found, number is updated to number = number // d and at the end of the while loop, if number > 1 you return True

Working through the code with number = 6:

isPrime2(6)
initialise> number := 6
initialise> d := 2
line3> check (2 * 2 < 6)     :True
line4> check (6 % 2 == 0)    :True
line5> update (number := 6//2) -> number = 3
line6> update (d : d + 1) -> d = 3
jump to line3
line3> check (3 * 3 < 3)      :False -> GOTO line7
line7> check(number > 1) -> check(3 > 1) :True
line8> return True -> 6 is prime
Xero Smith
  • 1,968
  • 1
  • 14
  • 19
  • isPrime1 was a function that I wrote, and isPrime2 was something that I modified which was actually intended to calculate Prime Factors of a number. The first function is working, let me work on the second one and fix it. Thanks – numersoz Oct 20 '17 at 05:50
0

Here is what I came up with

def is_prime(number):
    # if number is equal to or less than 1, return False
    if number <= 1:
        return False

    for x in range(2, number):
        # if number is divisble by x, return False
        if not number % x:
            return False
    return True
oguz ismail
  • 1
  • 16
  • 47
  • 69
ephrim
  • 17
  • 3
  • haufa. The first line of your function doesn't match the comment. The part `` not number % 2`` will return False for all odd numbers which means it will return False for every prime number except 2. Please modify the function accordingly. – Xero Smith Oct 20 '17 at 06:03
  • Your function is faster than my first one. isPrime1(1000000007) gave a result in 70 seconds and is_Prime(1000000007) gave a result in 60 seconds. Its better but lets see what other people have that would work faster. – numersoz Oct 20 '17 at 06:07
  • @XeroSmith I've made the changes. Thanks for the correction – ephrim Oct 20 '17 at 06:37
  • 1
    Testing up to `number` is a total waste. You can stop at `√number`. In the case of `1000000007`, this is about `30000` times faster. –  Jul 14 '19 at 13:50
  • 1
    Why do you only need to go up to the square root – Hacker Nov 30 '21 at 14:11