Puzzle 27: The Unpredictable I value
Your task is still to point out what the program will print.
Class Shifty
{
static void Main ()
{
int i = 0;
while ( -1 << i! = 0)
i++;
System.Console.WriteLine (i);
}
}
FAQ 27: The Unpredictable I value
The constant-1 is the int value (0xFFFFFFFF) that all 32 bits are set. The left-shift operator moves 0 into the lowest-right bit vacated by the shift, so the expression ( -1 << i) sets the rightmost I bit to 0 and keeps the remaining 32-i bits at 1. Obviously, this loop will complete 32 iterations, because ( -1 << i) is not equal to 0 for any I less than 32. You may expect the terminating condition test at I equals 32 o'clock to return false, which causes the program to print 32, but it does not print 32. In fact, it does not print anything, but enters an infinite loop.
The problem is that ( -1 << 32) equals-1 instead of 0,because the shift operator uses only the lower 5 bits of its right operand as the shift length. or a low 6 bit, if its left operand is a long type numeric value [C # Language Specification 7.8]. This rule acts on all two shift operators:<< and >>. The shift length is always between 0 and 31, or between 0 and 63 if the left operand is of type long. This length is for 32, and if the left operand is a long type, then the remainder is 64. If you attempt to shift 32 bits to an int value, or if you shift a long value to 64 bits, you can only return the value itself. There is no shift length that allows an int value to discard all of its 32 bits, or a long value to discard all its 64 bits.
Fortunately, there is a very easy way to fix the problem. Instead of having the 1 shift the different shift lengths repeatedly, we save the results of the previous shift operation and let it move 1 bits to the left at each iteration. The following version of the program can print the 32 we expect:
Class Shifty
{
static void Main ()
{
int distance = 0;
for (int val =-1; Val! = 0; Val <<= 1)
distance++;
System.Console.WriteLine (distance);
}
}
This revised procedure illustrates a common principle:if possible, the shift length should be constant. If the shift length is fixed on you, then you let the value exceed 31, or if the left operand is a long type, the likelihood of a value exceeding 63 is greatly reduced. Of course, it is not always possible to use constant shift lengths. When you must use a very long shift length, make sure that your program can cope with this problem-prone situation, or that it will not run into this situation at all.
The behavior of the shift operator mentioned earlier has another startling result. Many programmers want the right-shift operator with a negative shift length to act as a left-shift operator and vice versa. But this is not the case. The right-shift operator always moves to the right, and the left-shift operator always acts as a left-shift. The negative shift length is converted to a positive shift length by preserving only the lower 5 bits and removing the other bits-if the left operand is a long type, the lower 6 bits are retained. Therefore, if you want to move an int value to the left and its shift length is-1, then the effect of the shift is that it is shifted 31 bits to the left.
In summary, the shift length is 32 of the remainder, or if the left operand is long, then 64 is taken. Therefore, it is not possible to remove all bits of a numeric value by using any shift operator and shift length. At the same time, we cannot use the right-shift operator to perform a left-shift operation, or vice versa. If possible, use a constant shift length and be careful if the shift length cannot be set to constant.
The language designer might consider limiting the shift length to a range of type lengths from 0 to bits, and modifying the semantics of the shift length to type length so that it returns 0. While this avoids the clutter shown in this puzzle, it can lead to negative execution results because the semantics of C # Shift operators are the shift instruction semantics on many processors.
Copyright NOTICE: This article for Bo Master http://www.zuiniusn.com original article, without Bo Master permission not reproduced.
C # 27: The Unpredictable I value