The fractionSum problem#
The fractionSum is a favorite problem that shows in midterm tests now and then. The problem asks you to write a method, called fractionSum that accepts a double variable target and prints out the following output
1 + 1/2 + 1/3 + 1/4 + ...
with as many terms as it takes for the sum to just exceed the value of target.
The implementation for this problem is shown below.
public static void fractionSum(double target) {
double sum = 1.0; // min. possible value of sum
int n = 1; // first term in the sequence
System.out.print(n); // print the first term
while (sum < target) { // Keep adding until sum exceeds or equals target
n++; // move to the next term;
sum += 1.0/((double) n); // update sum
System.out.printf(" + 1/%d", n) // print term
} // done with while loop
System.out.printf(" = %f", sum) // print sum
} // method fractionSum
Key points
Fencepost affects mostly visual outputs (e.g., printouts).
Overcoming fencepost artifacts requires code duplication.
Fencepost is an loop artifact that becomes apparent usually when we require consistent or uniform presentation of data. For example, the code:
int N = 10;
for ( int i = 0; i < N; i++ ) {
System.out.print(i + ", ");
}
will produce the output
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
That last comma needs to go! The solution usually is to print the last (or the first) item separately. For example,
int N = 10;
for ( int i = 0; i < N - 1; i++ ) {
System.out.print(i + ", ");
}
System.out.print(N-1);
will produce the desired output, without a comma dangling after the last number.
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
We obtain the desired output at the cost of duplicating the print statement, to display the last value of the loop (N-1) outside the loop. This way, we allow the print statement inside the loop to print the commas separating the numbers. And the last statement to print a number without a comma following it.
Sometimes, the duplication of code can be problematic. Consider, for example, a method that parses the digits of an integer number and prints them in the form of a sum, e.g.,
23458 ---> 8 + 5 + 4 + 3 + 2
We start with the following code:
1public static void showDigits(int n) {
2 int r = n % 10;
3 n = n / 10;
4 System.out.print( r );
5 while ( n != 0 ) {
6 r = n % 10;
7 n = n / 10;
8 System.out.print( " + " + r );
9 }
10}
Notice, how lines 2 and 3 outside the loop above repeat as lines 6 and 7, within the loop. When we begin to see such duplication, it may be a good away to “factor” it away: move the repeating code into a method, and use that method in its place. In this example, if we move the repeating code in its own method, we’ll run to a fundamental Java problem. Let’s try it anyway.
1public static void showDigits(int n) {
2 doTheMath();
3 System.out.print( r );
4 while ( n != 0 ) {
5 doTheMath();
6 System.out.print( " + " + r );
7 }
8}
9
10public static ??? doTheMath(???) {
11 int r = n % 10;
12 n = n / 10;
13 return ???
14}
We can move the repeating operations in the new method doTheMath(), but how shall the method pass the results back? Java methods can return one and only one value. We cannot simply write
return r, n;
Java methods cannot return multiple values. In time, we learn to live with this limitation. And even come up with tricks to overcome it (e.g., we can return multiple values masquerading as an array which Java considers as a single value). For now, our only option is to make variables r and n accessible from every method in the class:
1public class FencePost {
2
3private static int n, r;
4
5 public static void showDigits() {
6 doTheMath();
7 System.out.print( r );
8 while ( n != 0 ) {
9 doTheMath();
10 System.out.print( " + " + r );
11 }
12 }
13
14 public static void doTheMath() {
15 r = n % 10;
16 n = n / 10;
17 }
18}