前言:
在项目中碰到一个打折的问题,例如用户在页面输入0.66,表示打6.6折,在数据库中是用float类型的字段保存的,保存的是0.66,然后数据库的float类型对应了java的一个double类型,后端需要把0.66取出来,然后乘以10,显示6.6折传给前端,但是在java里面,double类型的0.66乘以10,并不等于6.6,而是6.6000000000000005
查询了一下百度,才知道是精度损失的问题,所以就需要使用BigDecimal来进行计算
到后面才发现,有涉及到小数点的一定要使用 decimal 类型,别想着使用flaot或者double类型可以省点字节长度,因为不管使用的是double类型或者float类型的话,对应到java的都是double类型的属性,而在java中使用double类型会出现各种精度丢失的情况,比如定义1.30的一个值,使用System.out.println输出就会出现精度丢失的情况,更别说要参与各种加减乘除的运算了,而且使用double的时候,会自动把最后的一个0去掉,所以在项目中使用double,会造成各种的不便
初始化:
BigDecimal bigDecimal = new BigDecimal("3.00");
BigDecima类在初始化的时候,官方是建议直接使用字符串来作为参数进行实例化的
重点:
BigDecimal bigDecimalA = new BigDecimal("0.39");
BigDecimal bigDecimalB = new BigDecimal("0.3");
这两个在初始化的时候,虽然只是小数点后面的位数不一样,但是这个区别,在做乘法的时候就能很容易看出区别来。
bigDecimalA的小数点后面有两位,只要在做乘法的时候,最后两位如果不是0,那就会自动补0。例如 0.39 * 100 是39 ,但是在创建bigDecimalA对象的时候,是有小数点两位数的,然后会自动补00,所以算出来是39.00,例如0.39 *10 是3.9,现在小数点只有一位,然后就会再补一个0,所以算出来是3.90,再例如0.39 * 2 是0.78 现在算出来的结果已经有两位小数了,所以就不会再补0了
BigDecimal都是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象,所以在做加减乘除运算时千万要保存操作后的值。
计算:
public BigDecimal add(BigDecimal value); //加法
public BigDecimal subtract(BigDecimal value); //减法
public BigDecimal multiply(BigDecimal value); //乘法
public BigDecimal divide(BigDecimal value); //除法
除法,保留两位小数countSum.divide(a,2, RoundingMode.HALF_UP);除法之后取整数:
BigDecimal b1 = new BigDecimal("1256"); BigDecimal b2 = new BigDecimal("1000"); //四舍五入保留两位小数 BigDecimal b3=b1.divide(b2,2,BigDecimal.ROUND_HALF_UP); //输出:1.26 //向上取整 BigDecimal b4=b1.divide(b2,BigDecimal.ROUND_UP); //输出:2 //向下取整 BigDecimal b5=b1.divide(b2,BigDecimal.ROUND_DOWN); //输出:1 //保留两位小数向上取整 BigDecimal b6=b1.divide(b2,2,BigDecimal.ROUND_UP); //输出:1.26
直接取整:
BigDecimal b7 = new BigDecimal("12.51"); //保留一位小数向上取整 BigDecimal b8=b7.setScale( 1, BigDecimal.ROUND_UP); //输出 12.6 // 按照整数位向上取整 b7.setScale(0,BigDecimal.ROUND_UP); //输出 13 // 向下取整 b7.setScale(0,BigDecimal.ROUND_DOWN); //输出 12
BigDecimal四舍五入后保留两位小数
也可以使用这个方法来设置不够两位小数的时候,自动补0:BigDecimal.getPrice().setScale(2, RoundingMode.HALF_UP) 或者 BigDecimal.getPrice().setScale(2, 4)
![]()