《java解惑》笔记七

第二十五题:无情的增量操作

public static void main(String[] args) {
		int j = 0;
		for( int i = 0; i < 100 ; i++) {
			j = j++;
		}
		System.out.println(j);
	}
//控制台输出:
//0

这题考察了j = j++;这条语句,与下面语句等价:

int temp = j;
j = j + 1;
j = temp; 

以之相比 j = ++j;等价于下面代码:

j = j + 1;
int temp = j;
j = temp;

第二十六题:在循环中

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);
	}

这个程序是一个死循环,没有输出。关键在于i <= END,当i == END时,会执行i++,这时会产生溢出,i就成最小负数了,比END小,继续执行,陷入死循环。下面写了一个小例子,用来判断for循环执行顺序。

for(int i = 0;i < 3; i++,System.out.println("i++执行,i为"+i)) {
			System.out.println("循环语句执行,i为"+i);
		}
//控制台打印:
//循环语句执行,i为0
//i++执行,i为1
//循环语句执行,i为1
//i++执行,i为2
//循环语句执行,i为2
//i++执行,i为3

很显然,从控制台打印可以看出,for循环先执行int i = 0这条初始化语句,再执行i < 3这条语句为true,接着执行循环体,然后执行i++这条语句,再执行i<3这条判断。等到最后i为3时判断i<3为false结束循环。
总之,这里得到的教训是int不能表示所有整数,使用大整数时要注意溢出。

第二十七题:变幻莫测的i值

public static void main(String[] args) {
		int i = 0;
		while(-1<<i!=0) {
			i++;	
		}
		System.out.println(i);
	}

这个程序陷入死循环,根据java语言规范https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.19,引用如下:

If the promoted type of the left-hand operand is int, then only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.

如果左边操作数的提升类型是int,那么只有右边操作数的5个低序位被用作移位距离。就像右边操作数被服从于具有掩码值0X1F的位逻辑AND运算符&(15.22.1节),并具有掩码值0x1f(0b11111)。因此实际使用的移位距离始终在范围0~31之间,包含31。

实际上就是,在java中int移位,只能移0到31位,超出的取低5位,实际上就是取余。例如:i<<32,32%32 == 0,所以就是左移0位。类似的long移位,只能移0到63位,多的就取余。
所以程序中-1不能左移32位得0,陷入死循环。解决方法,书上已经给出,就是将每次结果保存,计数,得出结果。

第二十八题:循环者

public static void main(String[] args) {
//		int start = Integer.MAX_VALUE - 1;
//		for(int i = start;i <= start+1;i++) {}
		
		double i = 1.0 /0.0;
		double d = Double.POSITIVE_INFINITY;
		System.out.println(ChapterUtil.getIEE754FromDouble(i));
		System.out.println(ChapterUtil.getIEE754FromDouble(d));
//		while(i == i + 1) {}		
	}
//控制台输出:
//7ff0000000000000
//7ff0000000000000

如程序输出,double类型的正无穷大在内存存储为0x7ff0000000000000。
还有当i=1.0e40时,i+1==i。具体查看代码如下:

public static void main(String[] args) {	
		double i = 1.0e40;
		System.out.println(ChapterUtil.getIEE754FromDouble(i));
		System.out.println(ChapterUtil.getIEE754FromDouble(i+1));
		System.out.println(ChapterUtil.getIEE754FromDouble(i+Math.ulp(i)));
	}
//控制台输出:
//483d6329f1c35ca5
//483d6329f1c35ca5
//483d6329f1c35ca6

一个很大的浮点数与下一个浮点数之间间隔就不只是1了,它们之间间隔一个ulp,只要这个ulp>2,那么浮点数+1还是自身。
所以,得出的经验教训是:二进制的浮点运算,实际上是十进制运算的近似,当一个浮点数太大,另一个比较小时,运算就需要仔细考虑了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aabond

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值