`

谜题27-谜题34

阅读更多
谜题27:变化莫测的i值
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位而除去其他位的方式被转换为正的移位长度。
谜题31:循环者的鬼魂
请提供i的声明,使下面的循环变为一个无限循环
while(i!=0){
			i >>>=1;
		}

>>>为无符号右移,解决本谜题的关键在于>>>=是一个复合赋值操作符。它们可能会自动执行窄化原生类型转换,这种转换可能会丢失级数的信息,或是数值的精度。
假设申明如下 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,就不会。
总之,不要在char,short或byte类型的变量上应用复合运算符。
谜题32:循环者的诅咒
如何定义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上执行解包转换,并且在数字上比较所产生的数值,第三个表达式,比较的是对象引用
谜题33:循环者遇到了狼人
提供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也是。
谜题34:被计数击倒了
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的提升。这种提升会导致精度丢失的三种拓宽原生类型转换之一(另外两个是
从long到float和从long到double
,换句话说,(float)2000000050==2000000000。
不要使用浮点数作为循环索引。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics