Showing posts with label loop. Show all posts
Showing posts with label loop. Show all posts

Tuesday, March 2, 2010

Son of Looper

Son of Looper

Provide a declaration for i that turns this loop into an infinite loop:

while (i != i + 0) {

}



Unlike previous loopers, you must not use floating-point in your answer. In other words, you must not declare i to be of type double or float.



 



Solution : Son of Looper


Like the previous puzzle, this one seems impossible at first glance. After all, a number is always equal to itself plus 0, and you were forbidden from using floating-point, so you can't use NaN. There is no NaN equivalent for the integral types. What gives?



The inescapable conclusion is that the type of i must be non-numeric, and therein lies the solution. The only non-numeric type for which the + operator is defined is String. The + operator is overloaded: For the String type, it performs not addition but string concatenation. If one operand in the concatenation is of some type other than String, that operand is converted to a string prior to concatenation [JLS 15.18.1].



In fact, i can be initialized to any value so long as it is of type String; for example:




String i = "Buy seventeen copies of Effective Java!";



The int value 0 is converted to the String value "0" and appended to the blatant plug. The resulting string is not equal to the original as computed by the equals method, so it certainly can't be identical, as computed by the == operator. Therefore, the boolean expression (i != i + 0) evaluates to TRue and the loop never terminates.



In summary, operator overloading can be very misleading. The plus sign in the puzzle looks like addition, but it is made to perform string concatenation by choosing the correct type for the variable i, which is String. The puzzle is made even more misleading because the variable is named i, a name that is usually reserved for integer variables. Good variable, method, and class names are at least as important to program readability as good comments.

Bride of Looper

Bride of Looper

Provide a declaration for i that turns this loop into an infinite loop:

while (i != i) {

}






Solution : Bride of Looper


This looper is perhaps even more puzzling than the previous one. It really seems that it ought to terminate immediately, no matter what declaration precedes it. A number is always equal to itself, right?



Right, but IEEE 754 floating-point arithmetic reserves a special value to represent a quantity that is not a number [IEEE-754]. This value, known as NaN (short for "Not a Number"), is the value of all floating-point computations that do not have well-defined numeric values, such as 0.0 / 0.0. The specification says that NaN is not equal to any floating-point value, including itself [JLS 15.21.1]. Therefore, if i is initialized to NaN before the loop starts, the termination test (i != i) evaluates to TRue, and the loop never terminates. Strange but true.



You can initialize i with any floating-point arithmetic expression that evaluates to NaN; for example:




double i = 0.0 / 0.0;



Once again, you can add clarity by using a constant that is provided for you by the standard libraries:




double i = Double.NaN;



NaN holds other similar surprises. Any floating-point operation evaluates to NaN if one or more of its operands are NaN. This rule is perfectly reasonable, but it has strange consequences. For example, this program prints false:




class Test {

public static void main(String[] args) {

double i = 0.0 / 0.0;

System.out.println(i - i == 0);

}

}



The principle underlying the rules for computing with NaN is that once it generates NaN, a computation is damaged, and no further computation can repair the damage. The NaN value is intended to allow a damaged computation to proceed to a point where it is convenient to deal with the situation.



In summary, the float and double types have a special NaN value to represent a quantity that is not a number. The rules for computations involving NaN are simple and sensible, but the consequences of these rules can be counterintuitive.

Looper

Looper

This puzzle and the five that follow turn the tables on you. Instead of showing some code and asking what it does, they make you write the code, albeit in small amounts. These puzzles are called loopers. You will be shown a loop that looks as though it ought to terminate quickly, and it will be your job to come up with a variable declaration that makes it loop indefinitely, when placed immediately above the loop. For example, consider this for loop:

for (int i = start; i <= start + 1; i++) {

}



It looks as though it should run for only two iterations, but it can be made to loop indefinitely by taking advantage of the overflow behavior illustrated in (in the loop). The following declaration does the trick:




int start = Integer.MAX_VALUE - 1;



Now it's your turn. What declaration turns this loop into an infinite loop?




while (i == i + 1) {

}






Solution : Looper


Looking at the while loop, it really seems as though it ought to terminate immediately. A number is never equal to itself plus 1, right? Well, what if the number is infinity? Java mandates the use of IEEE 754 floating-point arithmetic [IEEE-754], which lets you represent infinity as a double or float. As we learned in school, infinity plus 1 is still infinity. If i is initialized to infinity before the loop starts, the termination test (i == i + 1) evaluates to true, and the loop never terminates.



You can initialize i with any floating-point arithmetic expression that evaluates to infinity; for example:




double i = 1.0 / 0.0;



Better yet, you can take advantage of a constant that is provided for you by the standard libraries:




double i = Double.POSITIVE_INFINITY;



In fact, you don't have to initialize i to infinity to make the loop spin forever. Any sufficiently large floating-point value will do; for example:



double i = 1.0e40;


This works because the larger a floating-point value, the larger the distance between the value and its successor. This distribution of floating-point values is a consequence of their representation with a fixed number of significant bits. Adding 1 to a floating-point value that is sufficiently large will not change the value, because it doesn't "bridge the gap" to its successor.



Floating-point operations return the floating-point value that is closest to their exact mathematical result. Once the distance between adjacent floating-point values is greater than 2, adding 1 to a floating-point value will have no effect, because the half-way point between values won't be reached. For the float type, the least magnitude beyond which adding 1 will have no effect is 225, or 33,554,432; for the double type, it is 254, or approximately 1.8 x 1016.



The distance between adjacent floating-point values is called an ulp, which is an acronym for unit in the last place. In release 5.0, the Math.ulp method was introduced to calculate the ulp of a float or double value.



In summary, it is possible to represent infinity as a double or a float. Most people find this somewhat surprising the first time they hear of it, perhaps because you can't represent infinity by using any of the integral types. Second, adding a small floating-point value to a large one will not change the large value. This too may be counterintuitive, as it isn't true for the real numbers. It is worth remembering that binary floating-point arithmetic is only an approximation to real arithmetic.

Shifty i's

Shifty i's

Like the program in the (In the loop), this one contains a loop that keeps track of how many iterations it takes to terminate. Unlike that program, this one uses the left-shift operator (<<). As usual, your job is to figure out what the program prints. When you read it, remember that Java uses two's-complement binary arithmetic, so the representation of -1 in any signed integral type (byte, short, int, or long) has all its bits set:


public class Shifty {

public static void main(String[] args) {

int i = 0;

while (-1 << i != 0)

i++;

System.out.println(i);

}

}



Solution : Shifty i's

The constant -1 is the int value with all 32 bits set (0xffffffff). The left-shift operator shifts zeroes in from the right to fill the low-order bits vacated by the shift, so the expression (-1 << i) has its rightmost i bits set to 0 and the remaining 32 - i bits set to 1. Clearly, the loop completes 32 iterations, as -1 << i is unequal to 0 for any i less than 32. You might expect the termination test to return false when i is 32, causing the program to print 32, but it doesn't print 32. In fact, it doesn't print anything but goes into an infinite loop.

The problem is that (-1 << 32) is equal to -1 rather than 0, because shift operators use only the five low-order bits of their right operand as the shift distance, or six bits if the left operand is a long [JLS 15.19]. This applies to all three shift operators: <<, >>, and >>>. The shift distance is always between 0 and 31, or 0 and 63 if the left operand is a long. It is calculated mod 32, or mod 64 if the left operand is a long. Attempting to shift an int value 32 bits or a long value 64 bits just returns the value itself. There is no shift distance that discards all 32 bits of an int value or all 64 bits of a long value.

Luckily, there is an easy way to fix the problem. Instead of repeatedly shifting -1 by a different shift distance, save the result of the previous shift operation and shift it one more bit to the left on each iteration. This version of the program prints 32 as expected:

public class Shifty {

public static void main(String[] args) {

int distance = 0;

for (int val = -1; val != 0; val <<= 1)

distance++;

System.out.println(distance);

}

}


The fixed program illustrates a general principle: Shift distances should, if possible, be constants. If the shift distance is staring you in the face, you are much less likely to exceed 31 or, if the left operand is a long, 63. Of course, it isn't always possible to use a constant shift distance. When you must use a nonconstant shift distance, make sure that your program can cope with this problematic case or does not encounter it.

There is another surprising consequence of the aforementioned behavior of shift operators. Many programmers expect a right-shift operator with a negative shift distance to function as a left shift and vice-versa. This is not the case. A right shift always functions as a right shift, and a left shift always functions as a left shift. Negative shift distances are made positive by lopping off all but the five low-order bits—six bits if the left operand is a long. So, for example, shifting an int to the left with a shift distance of -1 has the effect of shifting it 31 bits to the left.

In summary, shift distances are calculated mod 32 or, if the left operand is a long, mod 64. It is therefore impossible to shift away an entire value by using any shift operator or distance. Also, it is impossible to perform a left shift with a right-shift operator or vice-versa. Use a constant shift distance if possible, and exercise care if the shift distance can't be made constant.

Language designers should perhaps consider restricting shift distances to the range from 0 to the type size in bits and changing the semantics of shifting a value by the type size to return 0. Although this would avoid the confusion illustrated by this puzzle, it could have negative performance consequences; Java's semantics for the shift operators are those of the shift instructions on many processors.

In the Loop

In the Loop

The following program counts the number of iterations of a loop and prints the count when the loop terminates. What does it print?

public class InTheLoop {

public static final int END = Integer.MAX_VALUE;

public static final int START = END - 100;



public static void main(String[] args) {

int count = 0;

for (int i = START; i <= END; i++)

count++;

System.out.println(count);

}

}



Solution : In the Loop


If you don't look at the program very carefully, you might think that it prints 100; after all, END is 100 more than START. If you look a bit more carefully, you will see that the program doesn't use the typical loop idiom. Most loops continue as long as the loop index is less than the end value, but this one continues as long as the index is less than or equal to the end value. So it prints 101, right? Well, no. If you ran the program, you found that it prints nothing at all. Worse, it keeps running until you kill it. It never gets a chance to print count, because it's stuck in an infinite loop.



The problem is that the loop continues as long as the loop index (i) is less than or equal to Integer.MAX_VALUE, but all int variables are always less than or equal to Integer.MAX_VALUE. It is, after all, defined to be the highest int value in existence. When i gets to Integer.MAX_VALUE and is incremented, it silently wraps around to Integer.MIN_VALUE.



If you need a loop that iterates near the boundaries of the int values, you are better off using a long variable as the loop index. Simply changing the type of the loop index from int to long solves the problem, causing the program to print 101 as expected:




for (long i = START; i <= END; i++)



More generally, the lesson here is that ints are not integers. Whenever you use an integral type, be aware of the boundary conditions. What happens if the value underflows or overflows? Often it is best to use a larger type. (The integral types are byte, char, short, int, and long.)



It is possible to solve this problem without resorting to a long index variable, but it's not pretty:




int i = START;

do {

count++;

} while (i++ != END);



Given the paramount importance of clarity and simplicity, it is almost always better to use a long index under these circumstances, with perhaps one exception: If you are iterating over all (or nearly all) the int values, it's about twice as fast to stick with an int. Here is an idiom to apply a function f to all four billion int values:




// Apply the function f to all four billion int values

int i = Integer.MIN_VALUE;

do {

f(i);

} while (i++ != Integer.MAX_VALUE);



 


The lesson for language designers is : It may be worth considering support for arithmetic that does not overflow silently. Also, it may be worth providing support for loops designed specifically to iterate over ranges of integral values, as many languages do.