今天老师问了这么一个问题:
public class program {
//判断是否为奇数,是就返回true
public static boolean isOdd(int i){
return i % 2==1;
}
public static void main(String[] args){
for(int i=-2;i<=2;i++){
System.out.println(isOdd(i));
}
System.out.println("ssss"+(2-1.1));
}
}
//请问,这段程序将会输出什么?
//请解释并优化该代码
开始以为也没什么,但结果还是不容你想到的。
结果是:false false true false 0.8999999999999999
为什么是这样的呢?
其实是double的精度问题。0.1,无法用二进制精确表示,如果N是负数,10的N次幂无法用二进制精确表示。
既然不精确 如:(System.out.println(3-2.99); 输出:0.009999999999999787),总之差一点点,可以理解。在JAVA中要取得精确的带小数的值,用BigDecimal 即:System.out.println("优化后代码:"+new BigDecimal("2.00").subtract(new BigDecimal("1.10")));
==============================================================完美分界线
如下是转载 http://liuwei1981.iteye.com/blog/162891 的具体分析:
1.1这个数字不能被精确的表示为一个double,因此被表示为最接近它的double值。改程序从2中减去的就是这个值。遗憾的是,这个计算的结果并不是最接近0.9的double值。作为结果的double值的最短表示就是你看到的那个程序输出的可恶的数字。
并不是所有的小数都可以用二进制浮点数精确表示。如果使用的是JDK5或者更新的版本,那么您可能会受其诱惑,通过使用printf工具设置输出精度的方法改正程序:
- System.out.pringln("%.2f%n"2.00-1.10");
这条语句打印的结果正确,但并不表示它就是对底层问题的通用解决方案:它使用的仍旧是二进制浮点数的double运算。浮点运算在一个范围很广的值域上提供了很好的近似,但是通常不能产生精确的结果。二进制浮点对于货币计算是非常不合适的,因为它不可能将0.1或者10的其他任何次幂,精确的表示为一个有限长度的二进制小数。
解决该问题的一种方式就是使用某种整数类型。例如int或者long,并且以分为单位来执行计算。如果采纳了此路线,请确保改整数类型大到足以表示程序中将要用到的所有值。对该谜题来说,int就足够了。下面使用int类型,以分为单位表示货币值后重写的println语句:
- System.out.println((200-190) + "cents");
解决改问题的另一个方式就是使用执行精确小数运算的BigDecimal。它还可以通过JDBC与SQLDECIMAL类型进行互操作。这里要注意一点:一定要用BigDecimal(String)构造器,而千万不要用BigDecimal(double)。后一个构造器将用他的参数的精确值来创建一个实例。例如new BigDecimal(.1),它将返回一个BigDecimal,也即0.100000000000000055511151231257827021181583404541015625.正确使用BigDecimal,程序就可以输出我们所需要的结果0.90:
- import java.math.BigDecimal;
- public class Change{
- public static void main(String[] args){
- System.out.println(new BigDecimal("2.00").subtract(new BigDecimal("1.10")));
- }
- }
在需要精确答案的地方,要避免使用float和double;对于货币运算,要使用int,long,BigDecimal。