1

I am trying to figure out how this Java method calculates a prime number but something is confusing me.

public static boolean isPrime(int number){
    for(int divisor =2; divisor <= number / 2; divisor++){
        if (number % divisor ==0){
            return false;
        }
    }
    return true;
}

As you see in the second line in the for loop it shows divisor <= number /2 instead of divisor <= number. Can anyone tell me the reason for that?

  • 2
    Replace "divisor <= number / 2" by "divisor <=(int)Math.sqrt(number )+1" – Sebri Zouhaier Nov 18 '14 at 16:24
  • There's a lot going wrong with the idea of checking every divisor in a loop like this. It's very wasteful and inefficient. You don't need to check if divisible by 6 if you've already tested 2 or 3, etc. Optimally you should only check previous prime numbers up to root(number), but that requires storage of them. – Mark Fisher Nov 18 '14 at 16:44

8 Answers8

7

First, if you put divisor <= number, you would get no prime numbers at all, because every number is divisible by itself. If the loop does not exit before divisor becomes number, you would get to

number % divisor == 0

condition, and return false.

Whoever wrote this code made an observation that you can stop as soon as you have reached half the number, because if you did not find divisors in the lower half of the interval (2..number/2), there would be no divisors above half the number either, so you can declare the number prime without trying, unsuccessfully, the rest of the candidate divisors.

However, this is not the best you can do: a stronger condition can be used - you could compare divisor to square root of number. This works, because if you don't have a divisor that is less than or equal to the square root of number, there would be no divisors above the square root as well (it is a good idea to think why this is so).

int stop = Math.sqrt(number);
for(int divisor = 2; divisor <= stop ; divisor++) {
    ...
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • ohhh, yeees! I am so dumb to ignore the "if" statement there. So I think in this case it should be `divisor < number` to make it work although it is not necessary... But really thanks for the detailed explanation! :) – user1579701 Nov 18 '14 at 16:32
  • it's a shame the original code didn't pick up on the fact that you don't need to check every divisor from 2... number/2 (or root(num)), but only previous primes. Why check if divisible by 4 if you've already checked 2? or 6 if you've checked 3? – Mark Fisher Nov 18 '14 at 16:42
  • right, square root is a stronger condition. should thought about it! – user1579701 Nov 18 '14 at 16:50
  • @MarkFisher That is absolutely true! This algorithm presents a very nice opportunity to discuss the speed-for-memory tradeoff with your students. This is what Dijkstra discusses in his amazing [Notes on Structured Programming](https://www.cs.utexas.edu/users/EWD/ewd02xx/EWD249.PDF) on page 53. – Sergey Kalinichenko Nov 18 '14 at 16:51
  • @user1579701 In case you are curious, there is an amazing treatment of this problem in Dijkstra's article written back in 1969. I posted a link in a comment above. – Sergey Kalinichenko Nov 18 '14 at 16:54
3

The reason is is that any number can't be divided by any divisor larger than it's half and give more than 1 (if we are talking integers, of course).

Eugene Sh.
  • 17,802
  • 8
  • 40
  • 61
  • Ohh right! I am so dumb that I forget it can be simplified to reduce the unnecessary checking. But really thanks for the heads-up! :) – user1579701 Nov 18 '14 at 16:37
2

Any number would not be divisible by a number more than its half.

For example, the last number 10 would be divisible is 5. 10 is not divisible with 6, 7, 8 or 9.

This is why it's good to eliminate the obvious mismatches to improve the performance of the algorithm.

Kashif Nazar
  • 20,775
  • 5
  • 29
  • 46
1

As others have noted, there are no factors of n greater than n/2. A better solution is comparing your iterating variable to the square root of n, as if there are no factors less than or equal to the square root, there can't be any greater than the square root (Note that it is more efficient to compare i*i <= n that i <= Math.sqrt(n)).

An even better approach is the AKS primality test. If the number is 2 or 3, then it obviously must be prime. Otherwise, it can be rewritten in the form (6k+i) where i = -1, 0, 1, 2, 3, 4. Any (6k + 2) or (6k + 4) is divisible by 2, and any (6k + 3) is divisible by three, so the prime numbers must either take the form (6k - 1) or (6k + 1).

public static boolean isPrime(long n) { 
    /* This code uses the AKS primality test
     * http://en.wikipedia.org/wiki/AKS_primality_test
     */
    if (n <= 3) return n > 1;
    if (n % 2 == 0 || n % 3 == 0) return false;
    for (int i = 5; i*i <=n; i+=6) {
      if (n % i == 0 || n % (i+2) == 0) return false; 
    }
    return true;
  }
}

I used this as a part of my solution to the PrimeCounter problem in Sedgewick's Intro to Programming in Java (although this is in the first chapter before methods are introduced).

public class PrimeCounter {
  public static void main(String[] args) {
    long n = 10000000;
    long count = 0;
    for (long i = 0; i <= n; i++) {
      if (isPrime(i)) count++;
    }
    System.out.println("The number of primes less than "
                         + n + " is " + count);
  }


  public static boolean isPrime(long n) { 
    /* This code uses the AKS primality test
     * http://en.wikipedia.org/wiki/AKS_primality_test
     */
    if (n <= 3) return n > 1;
    if (n % 2 == 0 || n % 3 == 0) return false;
    for (int i = 5; i*i <=n; i+=6) {
      if (n % i == 0 || n % (i+2) == 0) return false; 
    }
    return true;
  }
}
Munyari
  • 85
  • 8
0

It's using the fact that if one of the factors is greater than N/2 the other must be smaller than 2.

In fact a massive (asymptotic) gain can be obtained by using the square-root.

That's because if one factor is greater than the square root the other is less.

Sorry Sebri Zouhaier. I'm changing allegiance. The +1 isn't necessary so the best answer is below. I'm sorry to change sides for such a tiny improvement!

Persixty
  • 8,165
  • 2
  • 13
  • 35
0

A number N cannot have any divisors D that are > N/2 and < N. To see this, note that if D is a divisor of N, then it must equal N/D2 for some D2. So the divisors of N are those values of this sequence that are integers: N, N/2, N/3, ... This is a descending sequence. It should be obvious that there can't be any divisors between N and N/2.

In fact, it's common for programs that check for primality to stop at sqrt(N) instead of N/2. The reason is this: Suppose there's a divisor D such that D > sqrt(N). Then N/D = D2 also must be a divisor of N. And it must be the case that D2 < sqrt(N), because if both D and D2 were > sqrt(N), then D * D2 would have to be > N, which is wrong because D * D2 = N. This means that there is no need to check possible divisors D > sqrt(N); if such a divisor existed, we already would have found D2 earlier in the loop and proven that N was not prime.

ajb
  • 31,309
  • 3
  • 58
  • 84
0

One small caveat to some of the above answers is that 0 and 1 are not prime numbers. You could account for this (for positive integers) with an implementation such as

public static boolean isPrime(int number){
    if (number == 0 || number == 1) 
        return false;
    else
    {
        int stop = (int) Math.sqrt(number);
        for (int divisor = 2; divisor <= stop ; divisor++) 
        {
               if (number % divisor ==0)
                    return false;

        }
            return true;

        }
    }
Alexander Kohler
  • 1,907
  • 16
  • 23
-1
public static Boolean isPrime(int num){ //method signature. returns Boolean, true if number isPrime, false if not
if(num==2){ //for case num=2, function returns true. detailed explanation underneath
  return(true);
}
for(int i=2;i<=(int)Math.sqrt(num)+1;i++){ //loops through 2 to sqrt(num). All you need to check- efficient
  if(num%i==0){ //if a divisor is found, its not prime. returns false
    return(false);
  }
}
return(true); //if all cases don't divide num, it is prime.

}


    // Returns true iff n is prime.  First checks if n is even, handling the
// cases of n=2 (prime) or n is even > 2 (not prime).  Then checks if any
// odd #'s between 3 and sqrt(n), inclusive, are divisors of n, returning
// false if any are.
public static boolean isPrime(int n) {
    if (n < 2) return false;
    if (n % 2 == 0)
        // n is an even, so return true iff n is exactly 2
        return (n == 2);
    for (int i=3; i*i<=n; i+=2)
        if (n % i == 0)
            // i divides evenly into n, so n is not prime
            return false;
    return true;
}
Sebri Zouhaier
  • 745
  • 7
  • 18
  • so many problems with this version. why are you testing divisible by every number in the 2,3,4,5,6,7...? if it's not divisible by 2 why check 4? and 8... same with 3 and 6, ... You only need to check previous primes. Also, your fast exit would be picked up in the first iteration of the loop, and do you really think it's going to catch that many cases it's worth writing into the method? – Mark Fisher Nov 18 '14 at 16:37