[b]谜题27:变化莫测的i值[/b]
因为-1左移32位是-1,因为移位操作符只使用右操作数的低5位作为移位长度。如果是long,使用低6位。负的移位长度只保留低5位而除去其他位的方式被转换为正的移位长度。
[b]谜题31:循环者的鬼魂[/b]
请提供i的声明,使下面的循环变为一个无限循环
>>>为无符号右移,解决本谜题的关键在于[color=red]>>>=是一个复合赋值操作符。它们可能会自动执行窄化原生类型转换[/color],这种转换可能会丢失级数的信息,或是数值的精度。
假设申明如下 short i = -1;
i的初始值((short)0xffff)非0,循环执行,在移位时,首先将i提升为int类型,所有的算术操作都会对short,byte和char类型的操作数执行这样的提升。结果得到int数值是0xffffffff,然后这个数值右移1位,得到0x7fffffff,最后这个数值被存回short类型的i中,执行可怕的窄化原生类型转换,直接截取低16位,得到((short)0xffff),
回到的原点。如果i声明为short或byte,并初始化为负数,都会得到死循环,如果是char,就不会。
[color=red]总之,不要在char,short或byte类型的变量上应用复合运算符。[/color]
[b]谜题32:循环者的诅咒[/b]
如何定义i,j,使下面的循环为无限循环?
用包装类定义Integer i = new Integer(0);
Integer j =new Integer(0);
前两个子表达式(i<=j和j<=i)在i和j上执行解包转换,并且在数字上比较所产生的数值,第三个表达式,比较的是对象引用
[b]谜题33:循环者遇到了狼人[/b]
提供i的定义,使下面循环无限
定义如下:int i = Integer.MIN_VALUE;或long i = Long.MIN_VALUE.
0具有唯一性的表示形式如果对int数值0取负,将得到0xffffffff+1,仍然是0。
但这也有个缺点,总共存在偶数个int数值,准确来说为2^32个,其中一个用来表示0,说明
正的和负的整数值的数量不等,至少有一个int数值,其负值不能正确的表示为int数值,
Integer.MIN_VALUE就是这样一个int数值,即-2^31,它的负值等于自身,Long也是。
[b]谜题34:被计数击倒了[/b]
why?循环变量是float类型,而非int型,很小的浮点数加到很大的浮点数上时,不会改变大浮点数的数值的,f的初始值接近Integer.MAX_VALUE,因此需要用31位表示,而float类型只能提供24位的精度。将一个int与一个float比较时,会自动执行从int到float的提升。这种提升会导致[color=red]精度丢失的三种拓宽原生类型转换之一(另外两个是
从long到float和从long到double[/color],换句话说,(float)2000000050==2000000000。
不要使用浮点数作为循环索引。
public class Main27 {
public static void main(String[] args) {
int i =0;
while(-1<<i!=0)i++; //无限循环
System.out.println(i);
}
}
因为-1左移32位是-1,因为移位操作符只使用右操作数的低5位作为移位长度。如果是long,使用低6位。负的移位长度只保留低5位而除去其他位的方式被转换为正的移位长度。
[b]谜题31:循环者的鬼魂[/b]
请提供i的声明,使下面的循环变为一个无限循环
while(i!=0){
i >>>=1;
}
>>>为无符号右移,解决本谜题的关键在于[color=red]>>>=是一个复合赋值操作符。它们可能会自动执行窄化原生类型转换[/color],这种转换可能会丢失级数的信息,或是数值的精度。
假设申明如下 short i = -1;
i的初始值((short)0xffff)非0,循环执行,在移位时,首先将i提升为int类型,所有的算术操作都会对short,byte和char类型的操作数执行这样的提升。结果得到int数值是0xffffffff,然后这个数值右移1位,得到0x7fffffff,最后这个数值被存回short类型的i中,执行可怕的窄化原生类型转换,直接截取低16位,得到((short)0xffff),
回到的原点。如果i声明为short或byte,并初始化为负数,都会得到死循环,如果是char,就不会。
[color=red]总之,不要在char,short或byte类型的变量上应用复合运算符。[/color]
[b]谜题32:循环者的诅咒[/b]
如何定义i,j,使下面的循环为无限循环?
while(i<=j&&j<=i&&i!=j){ }
用包装类定义Integer i = new Integer(0);
Integer j =new Integer(0);
前两个子表达式(i<=j和j<=i)在i和j上执行解包转换,并且在数字上比较所产生的数值,第三个表达式,比较的是对象引用
[b]谜题33:循环者遇到了狼人[/b]
提供i的定义,使下面循环无限
while(i!=0&&i==-i){ }
定义如下:int i = Integer.MIN_VALUE;或long i = Long.MIN_VALUE.
0具有唯一性的表示形式如果对int数值0取负,将得到0xffffffff+1,仍然是0。
但这也有个缺点,总共存在偶数个int数值,准确来说为2^32个,其中一个用来表示0,说明
正的和负的整数值的数量不等,至少有一个int数值,其负值不能正确的表示为int数值,
Integer.MIN_VALUE就是这样一个int数值,即-2^31,它的负值等于自身,Long也是。
[b]谜题34:被计数击倒了[/b]
public class Main34 {
public static void main(String[] args) {
final int START = 2000000000;
int count = 0;
for(float f = START;f<START+50;f++){
count++;
}
System.out.println(count); //0
}
}
why?循环变量是float类型,而非int型,很小的浮点数加到很大的浮点数上时,不会改变大浮点数的数值的,f的初始值接近Integer.MAX_VALUE,因此需要用31位表示,而float类型只能提供24位的精度。将一个int与一个float比较时,会自动执行从int到float的提升。这种提升会导致[color=red]精度丢失的三种拓宽原生类型转换之一(另外两个是
从long到float和从long到double[/color],换句话说,(float)2000000050==2000000000。
不要使用浮点数作为循环索引。