Recitation #3 – Discussion on solutons 1. Display prime numbers in the range [1, n], where n is a user-specified value. A number i is prime if its only factors are 1 and itself. A sample run is shown below: Enter upper value: 30 Primes up to 30: 2 3 5 7 11 13 17 19 23 29 Write the Java program PrintPrimes.java for this problem. Make your program works first, then make it modular by adding a method public static boolean isPrime(int a) to return true a is a prime, or false otherwise. 2. A sequence of numbers is monotonic increasing if the values are in sorted order. For example, 1, 1, 3, 4, 9 is a monotonic sequence, but 1, 3, 2, 4, 9 is not. Design and implement a program VerifyMonoIncreasing.java that determines whether its input sequence of integers is in monotonic increasing order. The input should terminate immediately once it is determined that the sequence is not monotonic increasing. A sample run is shown below: Enter a number: 3 Enter another number: 5 Enter another number: 5 Enter another number: 9 Enter another number: 12 Enter another number: <ctrl-d> (assume in UNIX) The sequence is monotonic increasing. Another sample run is shown below: Enter a number: 3 Enter another number: 5 Enter another number: 7 Enter another number: 6 The sequence is not monotonic increasing. - 1 of 5 - Discussion 1. (I have not tested out all the codes discussed here. Please test them out yourselves, and let me know if you spot any error.) Let’s begin with a simple version A, as shown below. The key for checking whether a value m is prime is to check if it can be divided by any of these values 2, 3, …, m-1. If so, then m is not a prime. // Version A System.out.print("Enter upper value: "); int n = scanner.nextInt(); System.out.println("Primes up to " + n + ":"); for (int m = 2; m <= n; ++m) { boolean isPrime = true; for (int i = 2; i < m; ++i) { if ((m % i) == 0) { isPrime = false; break; } } // print the result, if prime if (isPrime) System.out.println(m); } Some students queried why should isPrime be declared in the ‘for m’ loop, since doing so means that it is re-defined in every iteration. This is more of a matter of personal preference. The authors (Davidson and Cohoon) of the book happen to prefer this, following the guideline that a variable is defined at the place it is first assigned a value. I would prefer to define isPrime before the ‘for m’ loop, to avoid re-definition. Version B (only the relevant portion is shown) below eliminates the use of ‘break’, and put the Boolean variable isPrime in the loop condition. Some purists (mainly from the old school in teaching languages such as Pascal) argue that the usage of ‘break’ should be avoided at all cost, since the code can always be re-written without using ‘break’, as shown below. I take the moderate position that using ‘break’ sparingly is fine if it does not affect the readability of the code. In fact, some people feel that using ‘break’ appropriately may improve readability. (This shows that readability can be rather subjective.) Many application codes do use ‘break’. - 2 of 5 - // Version B for (int m = 2; m <= n; ++m) { boolean isPrime = true; for (int i = 2; (i < m) && isPrime; ++i) { if ((m % i) == 0) { isPrime = false; } } // print the result, if prime if (isPrime) System.out.println(m); } Version C below makes use of the mathematical fact that it is not necessary to check whether a value m is divisible by i in the range 2, 3, …, m – 1. It is sufficient to check for values of i in the range 2, 3, …, sqrt(m). Why? If a value m is indeed not a prime, say 18 (which is 2 9, or 3 6), then its factors (2 and 3) would have appeared in the range 2, 3, 4, and detected accordingly. In view of this, we test only up to sqrt(m). The code in version C tests up to sqrt(m) + 1 just in case sqrt(m) does not return an accurate answer. For example, sqrt(49) could be returned as 6.99999999 instead of 7, and casting it to an integer would result in 6. // Version C for (int m = 2; m <= n; ++m) { // only has to check values up to the square root int mSqrt = (int) Math.sqrt(m) + 1; // check all values up to the square root boolean isPrime = true; for (int i=2; (i <= mSqrt) && isPrime; ++i) { if ((m % i) == 0) { isPrime = false; } } // print the result, if prime if (isPrime) System.out.println(m); } Another enhancement can be made to the code. Except for the value 2, the other prime numbers cannot be even numbers. Therefore, we can cut down the number of iterations in the ‘for m’ loop by half by examining only odd numbers. This is shown in version D. - 3 of 5 - // Version D System.out.println(2); // 2 is a prime number // examining odd numbers for (int m = 3; m <= n; m+=2) { // only has to check values up to the square root int mSqrt = (int)Math.sqrt(m) + 1; // check all values up to the square root boolean isPrime = true; for (int i=2; (i <= mSqrt) && isPrime; ++i) { if ((m % i) == 0) { isPrime = false; } } // print the result, if prime if (isPrime) System.out.println(m); } By now, you should be convinced that there are quite a number of ways to code the program. You may go on to further enhance the code. For instance, Vo Huu Tien found out that for a prime number p, p%6 is either 1 or 5, and he enhanced his programming with this discovery. Primality test is a well-researched problem and you can find a lot of discussion and advanced research results on it on the Internet. I shall end the discussion for this question with a modular program, shown in version E below. // Version E public static boolean isPrime(int a) { if (a < 2) return false; else if (a == 2) return true; else { int aSqrt = (int) Math.sqrt(a) + 1; for (int i=2; i <= aSqrt; ++i) { if ((a % i) == 0) { return false; } return true; } } The method isPrime(a) returns true if a is a prime number, and false otherwise. We may then call this method in our main method as follows: for (int m = 2; m <= n; ++m) { if (isPrime(m)) System.out.println(m); } - 4 of 5 - 2. import java.util.*; public class VerifyMonoIncreasing { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); double previous = Double.MIN_VALUE; boolean isMonoIncreasing = true; int n; System.out.print("Enter a number: "); do { n = scanner.nextInt(); if (n >= previous) { previous = n; System.out.print("Enter another number: "); } else { isMonoIncreasing = false; } } while (isMonoIncreasing && scanner.hasNextInt()); // print the results if (isMonoIncreasing) { System.out.println("\nThe sequence is" + " monotonic increasing."); } else { System.out.println("The sequence is" + " not monotonic increasing."); } } } - 5 of 5 -