本文主要描述java损失精度的原因,在工作中多多少少都会遇到这个问题,遇到这个问题最好的解决办法就是用java.math.BigDecimal,用BigDecimal类型不会出现损失精度问题,在涉及到财务方面及其它精确计算的时候必用BigDecimal,BigDecimal相关用法请点击这个链接查看BigDecimal详解。
1.Java损失精度问题
1.1造成损失精度的原因
(1)强制类型转换损失精度(大范围转小范围有可能损失精度,小范围转大范围不会损失精度)
byte - short - char - int - long - float -double(从左往右小类型到大类型可以自动完成,也称为隐式类型转换)
(2)运算时溢出损失精度
当两个整数进行运算时, 其结果可能会超过整数的范围而发生溢出,正数过大而产生的溢出,结果为负数;负数过大而产生的溢出,结果为正数。1
2
3
4
5
6int a = 2147483647; //int类型整数的上限
int b = -2147483648; //int类型整数的下限
a = a + 1;
b = b - 1;
System.out.println("a=" + a); //输出结果: a=-2147483648 溢出,结果错误。
System.out.println("b=" + b); //输出结果: b=2147483647溢出,结果错误。
在溢出之前将一个值的类型往大的转1
2
3
4
5
6
7
8
9
10
11
12int a = 2147483647;
long d=(long)a+1;
System.out.println(d);
long b=(long)(a+1);
System.out.println(b);
long c=a+1;
System.out.println(c);
结果:
2147483648
-2147483648
-2147483648
(3)整型数据除法运算中的取整损失精度
若对两个整数相除,会舍弃小数的部分(注意:不是四舍五入),结果也是整数。
(4)浮点类型运算时会出现舍入误差
二进制系统中无法精确的表示1/10,就好像十进制系统中无法精确的表示1/3一样,计算机的运算底层都是二进制,而二进制无法精确表示浮点类型,导致计算时会有误差造成精度的损失。
1.2总结
(1)整型(int,long,short)与整型(int,long,short)进行计算只要结果不超过该结果类型的取值范围就不会损失精度(不算除法)。
(2)计算中只要有浮点类型参与运算(float,double)就有可能损失精度。
1.3扩展
(1)整数直接量是int(Java认为所有直接写出的整数都是int类型,超过int的表达范围,编译报错)
直接量三种表现形式:
int a = 100000; // 10进制
int b = 0x186a0; // 16进制
int c = 0303240; // 8进制
(2)浮点数直接量是double类型(如果需要表示float类型的直接量,需要加“f”或“F”后缀,float类型一般不常用)
(3)通过时间毫秒数来存储日期和时间
JDK提供 System.currentTimeMillis() 方法所经历的毫秒数,数据太大,故其数据类型为long
long time = System.currentTimeMillis();
(4)小类型到大类型的转换的细节问题看图