一、初始化
decimal 的初始化方式有四种
1、new decimal(int);
2、new decimal(long);
3、new decimal(dubbo);会有精度丢失的风险;使用BigDecimal d= BigDecimal.valueOf(dubbo);初始化dubbo
4、new decimal(String);小数最好使用字符初始化
二、计算方式
//加法 BigDecimal r1= v1.add(v2); //减法 BigDecimal r2= v1.subtract(v2); //乘法 BigDecimal r3= v1.multiply(v2); //除法 BigDecimal r4= v1.divide(v2);
三、为什么decimal中不能使用equal进行值比较,而是使用compareTo?
首先肯定是不会用==这种方式来使用哦,这个应该不用多说吧,BigDecimal属于对象,不是基本类型,不能用==来比较
BigDecimal r1= new BigDecimal(10); BigDecimal r2 = new BigDecimal(10); System.out.println(r1.equals(r2)); BigDecimal r3= new BigDecimal(10); BigDecimal r4= new BigDecimal(10.000); System.out.println(r3.equals(r4)); BigDecimal r5= new BigDecimal("10"); BigDecimal r6= new BigDecimal("10.000"); System.out.println(r5.equals(r6));
以上代码输出结果:true true false
针对equal对比为什么r1与r2是ture的,r3与r4也是ture,r5与r6是false
在源码中有一段
public class BigDecimal extends Number implements Comparable<BigDecimal> {
private final BigInteger intVal;
private final int scale;
private final transient long intCompact;
/**省略代码**/
public boolean equals(Object x) { if (!(x instanceof BigDecimal)) return false; BigDecimal xDec = (BigDecimal) x; if (x == this) return true; if (scale != xDec.scale) return false; long s = this.intCompact; long xs = xDec.intCompact; if (s != INFLATED) { if (xs == INFLATED) xs = compactValFor(xDec.intVal); return xs == s; } else if (xs != INFLATED) return xs == compactValFor(this.intVal); return this.inflated().equals(xDec.inflated()); }
equals不仅会比较数值,还会比较这个标度是否一样,也就是说equals会比较俩个参数,r5与r6的数值一样,但是scale不一样。而compareTo()这个方法只比较数值不比较scale标度。
然后我们来了解一下什么是scale:
如果scale为零或正值,则该值表示这个数字小数点右侧的位数。如果scale为负数,则该数字的真实值需要乘以10的该负数的绝对值的幂。例如,scale为-3,则这个数需要乘1000,即在末尾有3个0。
在BigDecimal有四种定义的类型,包括int、long、double、String四种,首先int和long类型都是整数,标度都是0。当类型是double的时候,new Bigdecimal(double) => new BigDecimale(0.1),实际传入的是0.1000000000000000055511151231527827021181583404541015625,这个时候的标度就是55,也就是小数点的个数。
而对于 new bigDecimal(1.0)来说,实际上就是整数,也就是不存在后缀,所以和整数的标度大小是一样的使用r3与r4为ture
四、最后了解
了解一下实际上一个BigDecimal是通过一个"无标度值"和一个"标度"来表示一个数的。
而无标度值的表示比较复杂。当unscaled value超过阈值(默认为Long.MAX_VALUE)时采用intVal字段存储unscaled value,intCompact字段存储Long.MIN_VALUE,否则对unscaled value进行压缩存储到long型的intCompact字段用于后续计算,intVal为空。
里面有一个scale标度的比较,大概这就是为什么r5和r6的比较结果是false的原因了。
五、放一个decimal的工具类
import java.math.BigDecimal; import java.math.RoundingMode; /** * @create: 2019-04-18 18:19 **/ public class BigDecimalUtil { public final static BigDecimal NEGATIVE_ONE = new BigDecimal(-1); public final static BigDecimal HUNDRED = new BigDecimal("100"); public final static BigDecimal TEN_THOUSAND = new BigDecimal("10000"); /** * 获取该数的相反数 * @param number 需要转换的数字 * @return java.math.BigDecimal * @date 2019/4/18 18:22 */ public static BigDecimal getOppositeNumber(BigDecimal number){ return notNull(number).multiply(NEGATIVE_ONE); } /** * 两数相减 * @param v1 被减数 * @param v2 减数 * @return java.math.BigDecimal * @date 2019/4/18 18:26 */ public static BigDecimal subtraction(BigDecimal v1, BigDecimal v2){ return notNull(v1).subtract(notNull(v2)); } /** * 两数相加 * @param v1 加数1 * @param v2 加数2 * @return java.math.BigDecimal * @date 2019/4/18 18:26 */ public static BigDecimal addition(BigDecimal v1, BigDecimal v2){ return notNull(v1).add(notNull(v2)); } /** * 两数相除 * @param v1 被除数 * @param v2 除数 * @param scale 保留小数位 * @return java.math.BigDecimal * @date 2020/1/6 17:24 */ public static BigDecimal division(BigDecimal v1, BigDecimal v2, int scale){ return division(v1, v2, scale, BigDecimal.ROUND_HALF_UP); } /** * 两数相除 * @param v1 被除数 * @param v2 除数 * @param scale 保留小数位 * @param roundingMode 保留模式 * @return java.math.BigDecimal * @date 2021/4/15 17:09 */ public static BigDecimal division(BigDecimal v1, BigDecimal v2, int scale, int roundingMode){ return notNull(v1).divide(notNull(v2), scale, roundingMode); } /** * 如果除数为null或为0,则返回0 * @param v1 被除数 * @param v2 除数 * @param scale 保留小数位 * @return java.math.BigDecimal * @date 2020/3/2 11:56 */ public static BigDecimal divisionIgnoreZero(BigDecimal v1, BigDecimal v2, int scale){ if (BigDecimalUtil.isEqualsZero(notNull(v2))){ return BigDecimal.ZERO; } return BigDecimalUtil.division(v1, v2, scale); } /** * 两数相乘 * @param v1 被乘数 * @param v2 乘数 * @param scale 保留小数位 * @return java.math.BigDecimal * @date 2020/1/6 17:24 */ public static BigDecimal multiply(BigDecimal v1, BigDecimal v2, int scale){ return notNull(v1).multiply(notNull(v2)).setScale(scale, RoundingMode.HALF_UP); } /** * 是否大于等于0 * @param v 需要判断的值 * @return boolean true:是;false:否 * @date 2019/4/19 11:15 */ public static boolean isGreaterAndEqualsZero(BigDecimal v){ int r = notNull(v).compareTo(BigDecimal.ZERO); return r > 0 || r == 0; } /** * v1是否大于等于v2 * @param v1 左边的值 * @param v2 右边的值 * @return boolean true:是;false:否 * @date 2019/4/19 11:15 */ public static boolean isGreaterAndEquals(BigDecimal v1, BigDecimal v2){ int r = notNull(v1).compareTo(notNull(v2)); return r > 0 || r == 0; } /** * v1是否大于v2 * @param v1 左边的值 * @param v2 右边的值 * @return boolean true:是;false:否 * @date 2021/4/22 14:53 */ public static boolean isGreater(BigDecimal v1, BigDecimal v2){ int r = notNull(v1).compareTo(notNull(v2)); return r > 0; } /** * v1是否等于0 * @param v1 需比较的值 * @return boolean true:是;false:否 * @date 2019/4/19 17:12 */ public static boolean isEqualsZero(BigDecimal v1){ int r = notNull(v1).compareTo(BigDecimal.ZERO); return r == 0; } /** * v1是否大于0 * @param v1 需比较的值 * @return boolean true:是;false:否 * @date 2019/4/19 17:12 */ public static boolean isGreaterZero(BigDecimal v1){ int r = notNull(v1).compareTo(BigDecimal.ZERO); return r > 0; } /** * v1是否等于v2 * @param v1 左边的值 * @param v2 右边的值 * @return boolean true:是;false:否 * @date 2019/6/10 16:52 */ public static boolean isEquals(BigDecimal v1, BigDecimal v2){ int r = notNull(v1).compareTo(notNull(v2)); return r == 0; } /** * 得到该数的正数 * @param v 需要转换的数字 * @return java.math.BigDecimal * @date 2019/6/12 14:41 */ public static BigDecimal getPositiveNumber(BigDecimal v){ if (!isGreaterZero(v)){ return getOppositeNumber(v); } return v; } /** * 得到该数的负数 * @param v 需要转换的数字 * @return java.math.BigDecimal * @date 2019/6/12 14:41 */ public static BigDecimal getNegativeNumber(BigDecimal v){ if (isGreaterZero(v)){ return getOppositeNumber(v); } return v; } /** * 获取非空的BigDecimal对象,为null则返回0 * @param value 需要判断的值 * @return java.math.BigDecimal 非空的BigDecimal对象 * @date 2019/12/25 10:28 */ public static BigDecimal notNull(BigDecimal value){ if (value == null) { return BigDecimal.ZERO; } return value; } /** * 获取两个数中比较小的值 * @param v1 第一个值 * @param v2 第二个值 * @return java.math.BigDecimal 比较小的值 * @date 2021/7/8 16:02 */ public static BigDecimal getLeast(BigDecimal v1, BigDecimal v2){ return notNull(v1).compareTo(notNull(v2)) > 0? v2: v1; } /** * 获取两个数中比较大的值 * @param v1 第一个值 * @param v2 第二个值 * @return java.math.BigDecimal 比较大的值 * @date 2021-07-20 17:35 */ public static BigDecimal getBigger(BigDecimal v1, BigDecimal v2){ return notNull(v1).compareTo(notNull(v2)) > 0? v1: v2; } /** * 获取百分比 * * @param v 需要转换为百分比的值 * @param scale 规模 * @return {@link BigDecimal } * @date 2021-10-11 15:32:49 */ public static BigDecimal getPercentage(BigDecimal v, int scale){ return BigDecimalUtil.multiply(v, HUNDRED, scale); } private BigDecimalUtil(){ } }