1

I'm in an intro to Java class and just finished an assignment, but I was left with a question in my head. I did not have time to ask my professor yet and it's a bit off topic from what we're doing anyhow.

Basically we had a program that will validate if a user inputted integer is prime or not. If it isn't prime, it calculates the closest prime number smaller than the input. For example:

Enter an integer: 4
4 is not a prime number. The closest prime number is 3.

The program works as intended using a loop if the input is not prime. Here is my code:

public static void main(String[] args) {

    Scanner input = new Scanner(System.in);
    int number;

    System.out.print("Please enter a positive, non-zero integer: ");
    number = input.nextInt();
    input.close();

    if (isValid(number) == true) {
        if(isPrime(number) == true) {
            System.out.printf("%d is a prime number.", number);
        } else {
            switch(number) {
                case 1: 
                    System.out.print("1 is not a prime number. \n");
                    System.out.print("We cannot find the nearest prime.");
                    break;
                default:
                    System.out.printf("%d is not a prime number.", number);
                    System.out.printf("\nThe nearest prime number is %d.", getNearestPrime(number));
                }
            }
        } else {
        System.out.print("Invalid input. Please run again.");
        System.exit(1);
    }   
}

public static boolean isValid(int number) {

    if (number > 0) {
        return true;
    } else {
        return false;
    }
}

public static boolean isPrime(int number) {

    int i;
    if(number == 1) {
        return false;
    } else {
        for(i = 2; i < number; i++) {
            if(number%i == 0) {
                return false;
            }
        }
        return true;
    }
}

public static int getNearestPrime(int number) {

    do {
        number--;
    } while (isPrime(number) == false);

    return number;
}

It's important to note we were required to create the three methods listed below main.

My question is this: is there a way to increase performance when calculating larger ints in this scenario?

If I was to input 2,147,483,647, the program takes about 10 seconds to recognize it's prime. If I enter 2,147,483,646, it takes roughly the same time to find the closest prime.

I completely understand why this happens, but it seems like any high level Java applications I've used can computer way more complex things much faster than my simple program can.

I'm genuinely just curious how experienced programmers handle something like this. Thank you!

Anthony
  • 11
  • 1
  • 2
    There are several ways by which the performance of this code could be *substantially* improved. Some of them are pretty straightforward, such as approaches based on [prime number sieves](https://en.wikipedia.org/wiki/Generating_primes#Prime_sieves). Unfortunately, the question as posed is too broad for Stack Overflow, but you might consider asking over in [Code Review](https://codereview.stackexchange.com/), however. Be sure to first check [their criteria](https://codereview.stackexchange.com/help/asking), though. – John Bollinger Jul 26 '18 at 20:50
  • @JohnBollinger Interesting, I appreciate the response. I just looked up prime number sieves, and correct me if I'm wrong but wouldn't that require other methods and whatnot? I probably should've added we were only allowed to use isValid(), isPrime(), and getNearestPrime() - nothing further. Thank you for pointing me to code review also! – Anthony Jul 26 '18 at 20:53
  • No, there is no particular reason why additional methods would be needed, though a restriction to not implement any additional methods is pretty artificial. – John Bollinger Jul 26 '18 at 20:54
  • If you (or some other visitor) ever deal with bigger integers, you might be interested in the Wikipedia article for [Primality test](https://en.wikipedia.org/wiki/Primality_test) and also [java.math.BigInteger.isProbablePrime(int)](https://docs.oracle.com/javase/8/docs/api/java/math/BigInteger.html#isProbablePrime-int-). – MvG Jul 26 '18 at 21:02
  • The biggest single change to improve performance, which is also simple to implement, is the one already mentioned by @JohnBollinger : only loop up to the square root of the number being tested in method **isPrime()**. Any additional looping after that is pointless. – skomisa Jul 27 '18 at 01:50

2 Answers2

3

Several simple things you can change:

1) A prime number will never be even, so once you check if a number is divisible by two, you don't need to check if it is divisible by any other even number. So you can simplify your loop a little. (Just add an if statement to check if the number is 2 and then start i at three)

2) You only have to loop until the square root of the number.

  int i;
  if(number == 1) {
      return false;
  }
  if(number == 2) {
     return true; //2 is a prime number
  } 
  if (number % 2 == 0) {
     return false;
  }
  for(i = 3; i* i <= number; i+=2) {
      if(number%i == 0) {
          return false;
      }
  }
  return true;
GBlodgett
  • 12,704
  • 4
  • 31
  • 45
  • 1
    No, no, no. Do not bring floating-point math into this, nor, for that matter, needless method invocations. `i * i <= number` will do just fine. – John Bollinger Jul 26 '18 at 20:58
  • @JohnBollinger That would be a better way of doing it wouldn't it.. Thanks for the excellent suggestion! – GBlodgett Jul 26 '18 at 21:00
  • 1
    @GBlodgett Off topic, but why does the code comment state that "2 is **technically** a prime number"? It's just as much a prime number as any other prime number. – skomisa Jul 27 '18 at 01:16
0

Well one thing to note is that algorithmic wise there are more efficient algorithms to use. See this answer for details

Regarding implementation you can for example employ some tricks such as caching of recent results if you want to increase performance. A more efficient approach but perhaps outside the scope of a course would be to use a list of precalculated primes. You can find one in the internet or you can run a program once to precalculate them up to a given point.

Do note that this approach would trade off some memory for the sake of speed.

Spyros K
  • 2,480
  • 1
  • 20
  • 37