谜题2:找零时刻
有如下问题:
我去商店买了一包1.1块的东西,身上有2块钱,请问老板该找我多少钱?
这个题小学生都会做,但是我们是未来的程序猿,所以得用代码来实现.(原谅我这一生放荡不羁爱逗比…)
public class Change {
public static void main(String[] args){
System.out.println(2.0 - 1.1);
}
}
It’s so easy….
But….
为什么会这样?
这就是一个坑啊!!
解释:
问题出在1.1
这个数字不能被精确的表示为一个double
,因此它被表示称为最接近它的double值.该程序从2中减去的就是这个值.但是这个计算的结果并不是最接近0.9
的double
值.表示结果的double
值的最短表示就是你所看到的打印出来的那个数字.
更准确的说是不是所有的小数都可以用二进制浮点数来精确表示的.
我们可以用System.out.printf("%.2f%n",2.00-1.10);
来打印我们想要的正确答案,就像回到了C语言一样.但是只是截取了我们希望得到的小数点后2位数,底层依旧还是二进制浮点数的double运算.
解决方法:
使用执行精确小数运算的BigDecimal
;
但是最好使用BigDecimal(String)
构造器,而不是使用BigDecimal(double)
构造器,后一个构造器将用他的参数的精确值来创建一个对象, new BigDecmal(0.1)
将返回0.1000000000000000055511151231257827021181583404541015625
这么长,我也是醉了
接下里来就是见证奇迹的时刻了…
System.out.println(new BigDecimal("2.0").subtract(new BigDecimal("1.1")));
成功输出0.9
这样其实不是最好的,因为java没有为BigDecimal
提供任何语言上的支持,使用BigDecimal
很有可能会比其他使用原始数据类型的计算要慢一些.
反正这么一折腾,我是明白了在需要精确答案的地方,要避免使用float
和double
;对于货币计算,使用int,long
或BigDecimal
会更好.