Recitation #3 – Discussion on solutons

advertisement
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 -
Download