我们先来看一小段故事和解决该问题的代码.
Tom在一家汽车配件商店购买了一个价格为$1.10的火花塞,但是他的钱包里都是面额为两美元的钞票.当他用一张两美元的钞票来支付这个火花塞,那么销售员应该找给Tom多少零钱呢?
//下面是一段大家可能都会认可的代码
public class Test{
public static void main(String[] args){
System.out.println(2.00 - 1.10);
}
}
/*你可能会天真地认为该程序代码能够实现,并且打印出正确结果0.90.
当然你的感觉是有一定道理的,如果你对Double.toString文档中设定的将double类型的值转换为String(字符串)的规则有点了解,你就会觉得该程序打印出来的小数是足以将double类型的值与最靠近它的临近值区分并打印出来的,它在小数点之前和之后都至少有一位.
*/
所以,你的直觉看起来还蛮有道理的~,
那么结果到底如何呢?如果你打印后就会发现它打印的是0.8999999999999999
这是为什么呢?
问题在于1.1这个数字并不能被精确的表示为一个double,它只能被表示最近它的double值.上面的代码就是试图从2中减去这个值,遗憾的是这个计算的结果并不是最接近的0.9的double值,所以打印出的就是你没想到的那个邪恶的值.直接的说,并不是所有的小数都可以用二进制浮点数来精确表示.!
下面有几种解决的方案:
1,依旧使用二进制浮点数
2,使用整数类型,例如:int或long
3,使用执行精确小数运算的BigDecimal想了解~下面就是用三种方式实现的代码(控制台有打印出的结果)
但有一点就是,Java并没有为BigDecimal提供任何语言上的支持.所以大家可能稍微有些陌生.......
使用BigDecimal的计算很有可能比那些使用原始类型的计算要慢一些,对某些大量使用小数计算的程序来说,这可能会成为问题,而对大多数程序来说,这显得一点也不重要。
总之, 在需要精确答案的地方,要避免使用float和double;对于货币计算,要使用int、long或BigDecimal。对于语言设计者来说,应该考虑对小数运算提供语言支持。一种方式是提供对操作符重载的有限支持,以使得运算符可以被塑造为能够对数值引用类型起作用,例如BigDecimal。