java解惑(谜题一到5)

java解惑(谜题1到5)
问题1:判断整数是否是奇数
public static boolean isOdd(int a){ 
		return (a%2)!=0;
//		return (a&1)!=0;    性能优化
		
//		return  (a%2)==1;                不可,负奇数的余数是-1
	}


问题2:小数运算

System.out.println(2.00-1.10);    //0.8999999999999999
解释:1.1不能被准确表示为一个double,因此被表示为最接近它的double值。
并不是所有小数都可以用二进制浮点数准确表示
System.out.printf("%.2f%n", 2.00-1.10); //0.90
		System.out.println(new BigDecimal("2.00").subtract(new BigDecimal("1.10"))); //0.90

一定使用的是BigDeciaml(String)的构造器,而不是BigDeciaml(double)
总之,在需要精确答案的地方,不要使用float和double

问题3:长整除
public class Main {

	public static void main(String[] args) {
		
	final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;// 86400000000
		final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000 ;
		System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY);// 5
	}
	}


因为是按照int运算的,两个int相乘,结果为int型,溢出了。
修改如下:即可打印预期结果
final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000;
教训:当操作很大的数字时,千万要提防溢出。
问题4:初级问题
问题3是除法,比较复杂,下面的例子只涉及加法,结果如何呢?
System.out.println(12345+5432l);

一定以为打印出66666,而结果是17777,请认真注意第二个操作数为5432l,是一个long型数。教训:在long类型字面常量中,一定要用大写的L,不要用小写的l,容易与1混淆。还要避免用单个l做变量名
问题5:十六进制的趣事
System.out.println(Long.toHexString(0x100000000L+0xcafebabe));

看似应打印出1cafebabe,但结果是cafebabe。为何?
所有的十进制字面常量都是正数,如果想写一个负的十进制,则需要在正的十进制字面常量前加上“-”即可。但是,十六进制或八进制字面常量可就不一定是正数或负数,是正还是负,则要根据当前情况看:如果十六进制和八进制字面常量的最高位被设置成了1,那么它们就是负数。
该程序执行的加法是一个混合类型的计算:左操作数是long型,而右操作数是int类型。为了执行该计算,Java将int类型的数值用拓宽原生类型转换提升为long类型,然后对两个long类型数值相加。因为int是有符号的整数类型,所以这个转换执行的是符号扩展。
这个加法的右操作数0xcafebabe为32位,将被提升为long类型的数值0xffffffffcafebabeL,之后这个数值加上了左操作0x100000000L。当视为int类型时,经过符号扩展之后的右操作数的高32位是-1,而左操作数的第32位是1,两个数值相加得到了0:
0x 0xffffffffcafebabeL
+0x 0000000100000000L
-----------------------------
0x 00000000cafebabeL
如果要得到正确的结果0x1cafebabe,则需在第二个操作数组后加上“L”明确看作是正的long型即可,此时相加时拓展符号位就为0:
System.out.println(Long.toHexString(0x100000000L + 0xcafebabeL));//1cafebabe
最好避免混合运算