double和float为什么不能精确计算
在计算机中,为了提高运算效率,数值型使用二进制进行运算,但是对于double和float这类小数来说,不是所有的十进制数都能转化为有限位二进制数的,也就是十进制整数在转化成二进制数时会有精度问题,常会使用近似值替代原小数完成运算,这就导致使用double和floa进行计算可能出现误差。
相关知识:
BigDecimal的基础使用
构造器
-
BigDecimal(int)
创建一个具有参数所指定整数值的对象
-
BigDecimal(double)
创建一个具有参数所指定双精度值的对象
-
BigDecimal(long)
创建一个具有参数所指定长整数值的对象
-
BigDecimal(String)
创建一个具有参数所指定以字符串表示的数值的对象
注意:对于小数,推荐使用BigDecimal(double)而不推荐使用BigDecimal(String)
加减乘除
-
BigDecimal add(BigDecimal):加法。将BigDecimal对象中的值加上入参,然后返回
-
BigDecimal subtract(BigDecimal):减法。将BigDecimal对象中的值减去入参,然后返回
-
BigDecimal multiply(BigDecimal):乘法。将BigDecimal对象中的值乘上入参,然后返回
-
BigDecimal add(BigDecimal):除法。将BigDecimal对象中的值除以入参,然后返回商
精度的使用
BigDecimal setScale(int scale, RoundingMode roundingMode)
:设置精度。对BigDecimal数据小数点后的位数进行进位、舍位、截断等操作。scale是精度值,roundingMode是舍入规则如四舍五入等。
对于加减乘除方法,也可以使用相应的重载方法如BigDecimal add(BigDecimal,)
舍入规则:
-
ROUND_CEILING:舍向正无穷
-
ROUND_UP:直接加1
-
ROUND_DOWN:直接舍弃掉后面的数
-
ROUND_FLOOR:舍向负无穷
-
ROUND_HALF_DOWN:四舍五入,大于5向前进1
-
ROUND_HALF_EVEN:接近负无穷大的舍入模式
-
DOUND_HALF_UP:四舍五入,大于等于5向前进1
大小比较
-
BigDecimal equals(BigDecimal):判断是否相等,值和精度相等时返回true,否则返回false
-
BigDecimal compareTo(BigDecimal):比较大小。大于返回1,小于返回-1,等于返回0
BigDecimal需要注意的坑
正确使用构造器
对于小数,推荐使用BigDecimal(double)而不推荐使用BigDecimal(String)。
参数类型为double的构造方法的结果有一定的不可预知性。有人可能认为在Java中写入newBigDecimal(0.1)所创建的BigDecimal正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法准确地表示为 double(
或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。String 构造方法是完全可预知的:写入 newBigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言, 通常建议优先使用String构造方法。
当double必须用作BigDecimal的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用Double.toString(double)方法,然后使用BigDecimal(String)构造方法,将double转换为String。要获取该结果,请使用static valueOf(double)方法。
使用compareTo()比较
BigDecimal的equals
方法,当且仅当指定的Object是一个BigDecimal,其值和比例都等于该BigDecimal时才返回true。
BigDecimal的compareTo
方法,只需要值相等即返回true。
在开发中使用BigDecimal比较是否相等时,应当注意使用equals还是compareTo。
divide使用精度控制避免除不尽
在进行除法运算的时候,结果不能整除,有余数,这个时候会报java.lang.ArithmeticException,在实际使用中,为了避免这个错误,在进行除法运算的时候,使用divede(BigDeciaml divisor,int scale,int roundingMode),scale是要保留的小数位数,roundingMode是保留规则。
在开发中,凡是使用除法运算时,都应传入scale和roundingMode两个参数
BigDecimal“不可变”应该返回新对象
在使用BigDecimal的方法,如setScale、add等方法时,应该返回一个新的BigDecimal使用,原BigDecimal是不可变的。