我们知道在计算机中存储小数是通过整数部分正常的取其
补码
,但是小数部分是通过乘2取整直到余0为止
的方式去表示的。
也就是说浮点数8个字节(64个bit)的长度,如果其小数部分无限循环的话,最后表示出来的数据也只能无限接近这个准确值。例如用浮点数表示1/3
。
比如我现在去楼下超市买了一瓶1.9的矿泉水。我拿了一张5元的人民币,理论上找回金额的代码应该这么写的
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("请输入多个数字判断奇偶:");
while(input.hasNextInt()) {
System.out.println(10.00-9.60);
}
}
可是。。。让人很失望!!
运行结果:
0.40000000000000036
命运似乎开了天大的玩笑,不过想想也对呀! 0.4本来就是用二进制无法准确表示的的呀,乘2取余取到0为止
对0.4来说循环是根本停不来。所以才会出现这种情况。
我们可能会想到这样取整:
public static void main(String[] args) {
NumberFormat format = new DecimalFormat("#.##");
System.out.println(format.format(10.00-9.60));
}
查看运行结果等于0.4,貌似解决了问题,然而对于我们当前场景,你可能觉得这点误差没啥,但是如果在金融行业,这点误差可能带来无法估量的损失。解决方法有如下:
- 其实Java中有专门弥补浮点数无法精确计算缺憾而设计的类
BigDecimal
,它提供了常用的数学算法加减乘除,特别是和数据库的Decimal类型字段映射时,BigDecimal
是最佳解决方案。
*2.当然在一些要求不是很高的行业,比如超市等零售行业,我们一般采用将小数先扩大,在进行运算,最后缩小回去就可以,这种方法简单快速。