用整数类型处理货币

涉及到支付问题,有时相减会出现意外的结果:

public class testPay {
	public static void main(String[] args) {
		System.out.println(10.00 - 9.60);
	}
}
//结果:0.40000000000000036
**System.out.println(10.00 - 9.60); 编译的class文件使用jad反编译后**
System.out.println(0.40000000000000036D);

原因:这是因为在计算机中浮点数有可能(注意是可能)是不准确的,它只能无限接近准确值,而不能完全精确。为什么会如此呢?这是由浮点数的存储规则所决定的,我们先来看0.4这个十进制小数如何转换成二进制小数,使用“乘2取整,顺序排列”法(不懂?这就没招了,太基础了),我们发现0.4不能使用二进制准确的表示,在二进制数世界里它是一个无限循环的小数,也就是说,“展示”都不能“展示”,更别说是在内存中存储了(浮点数的存储包括三部分:符号位、指数位、尾数,具体不再介绍),可以这样理解,在十进制的世界里没有办法准确表示1/3,那在二进制世界里当然也无法准确表示1/5(如果二进制也有分数的话倒是可以表示),在二进制的世界里1/5是一个无限循环小数。

详细可以查看 IEEE二进制浮点数算术标准

表示方法:符号位 + 幂指位 + 数值位

符号位 幂指位 数值位
float 1 8 23
double 1 11 52

0.4
符号位 :0
幂指位:01111111 (默认值)
数值位: 01100110 01100110 0110011
0.4 * 2 = 0.8 0
0.8 * 2 = 1.6 1
0.6 * 2 = 1.2 1
0.2 * 2 = 0.4 0
0.4 * 2 = 0.8 0

用整数类型处理货币_第1张图片
错误处理:
结果是0.4,看似解决了,大批量数据还是会出现误差。

import java.text.DecimalFormat;
import java.text.NumberFormat;

public class testPay {
	public static void main(String[] args) {
//		System.out.println(10.00 - 9.60);
		NumberFormat f = new DecimalFormat("#.##");
		System.out.println(f.format(10.00 - 9.60)); 
		//结果 0.4
	}
}

解决方法
A:使用BigDecimal BigDecimal是专门为弥补浮点数无法精确计算的缺憾而设计的类,并且它本身也提供了加减乘除的常用数学算法。Java BigDecimal详解 http://blog.csdn.net/jackiehff/article/details/8582449
Android除法运算,保留小数

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;

public class testPay {
	public static void main(String[] args) {
		// System.out.println(10.00 - 9.60);
		// NumberFormat f = new DecimalFormat("#.##");
		// System.out.println(f.format(10.00 - 9.60)); //结果 0.4
		BigDecimal b1 = new BigDecimal(Double.toString(10.00));
		BigDecimal b2 = new BigDecimal(Double.toString(9.60));
		System.out.println(b1.subtract(b2).doubleValue()); // 结果 0.4
	}
}

B:使用整型 把参与运算的值扩大100倍,并转变为整型,然后在展现时再缩小100倍。之前项目上使用的银联支付传的价格单位就是分,用的就是这个方法。

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;

public class testPay {
	public static void main(String[] args) {
		// System.out.println(10.00 - 9.60);
		// NumberFormat f = new DecimalFormat("#.##");
		// System.out.println(f.format(10.00 - 9.60)); //结果 0.4
		// 使用BigDecimal
		// BigDecimal b1 = new BigDecimal(Double.toString(10.00));
		// BigDecimal b2 = new BigDecimal(Double.toString(9.60));
		// System.out.println(b1.subtract(b2).doubleValue()); // 结果 0.4
		// 扩大100倍 在缩小
		System.out.println((10.00 * 100 - 9.60 * 100) / 100);// 结果 0.4
	}
}

我是IT小王,如果喜欢我的文章,可以扫码关注我的微信公众号

你可能感兴趣的:(java学习笔记)