谜题2:找零时刻
1、有一张2元的钞票,买了一个价值1.10元的物品,那么应该找给他多少钱呢?
package chapter.one;
import java.math.BigDecimal;
/**
* @author Nass
* @date 2019/11/13 19:30
*/
public class Change {
public static void main(String[] args) {
System.out.println(2.00-1.10);
System.out.println(2.00-1.25);
}
}
运行结果:
0.8999999999999999
0.75
显然这和我们想要的结果(0.90)是不一致的。
原因:
1.1(十进制) = 1.0001100110011001(二进制) 超出计算精度,结果保留十六位小数
1.10 = 20+1/(24) + 1/(2^5) + 1/(2^8) + …
其中1.1只能无限循环下去,这就意味着0.1在计算机中不能被精确表示
1.25(十进制) = 1.01(二进制)
1.25 = 20+1/(22)
1.25可以在计算机中精确表示
并不是所有的小数都可以用二进制浮点数精确表示::
二进制浮点对于货币计算是非常不适合的,因为它不可能将0.1或者10的其它任何次负幂——精确表示为一个长度有限的二进制小数
2、解决方法
使用BigDecimal:
一定要用BigDecimal(String)构造器,千万不要用BigDecimal(double)构造器。
BigDecimal a = new BigDecimal("2.00");
System.out.println(a);
BigDecimal b = new BigDecimal(1.10);
System.out.println(b);
BigDecimal result = new BigDecimal("2.00").subtract(new BigDecimal("1.10"))
System.out.println(result);
运行结果:
2.00
1.100000000000000088817841970012523233890533447265625
result = 0.90
3、警示⚠️
在需要精确答案的地方,要避免使用float和double;对于货币计算,要使用int、long、BigDecimal。