Java 大小数类型 (BigDecimal)

1. double 类型

@Test
public void doubleDemo() {
    double d1 = 1.0;
    double d2 = 0.9;
    // 0.09999999999999998
    double value = d1 - d2;

    // 0.9999999999999999
    double result = (1.4 - 0.5) / 0.9;
}

double 是近似值存储,若需要进行高精度计算,采用 BigDecimal

2. BigDecimal 类型

  • 作用:精确计算浮点数,常用于财务计算
public class BigDecimal extends Number implements Comparable {
    private final BigInteger intVal;
    private final int scale; 

    // 一般采用参数为字符串的构造方法,可以保证精度不会丢失
    public BigDecimal(String val) {
        this(val.toCharArray(), 0, val.length());
    }

    public BigDecimal add(BigDecimal augend) {}
    public BigDecimal subtract(BigDecimal subtrahend) {}
    public BigDecimal multiply(BigDecimal multiplicand) {}
    /**
     * scale 小数位
     * roundingModel 小数位舍入模式
     */
    public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {}

    // Returns: -1, 0, or 1 as this BigDecimal is numerically less than, equal to, or greater than val.
    public int compareTo(BigDecimal val) {}
}

2.1 四则运算

@Test
public void arithmetic() {
    BigDecimal b1 = new BigDecimal("1.0");
    BigDecimal b2 = new BigDecimal("0.9");
    BigDecimal add = b1.add(b2);
    BigDecimal subtract = b1.subtract(b2);
    BigDecimal multiply = b1.multiply(b2);

    // 链式写法
    BigDecimal divide1 = b1.add(b2).divide(new BigDecimal("0.2"));
    System.out.println(divide1);
}

2.2 除法运算

@Test
public void divide() {
    BigDecimal divide = new BigDecimal("10").divide(new BigDecimal("3"));
}

注意:除不尽时会报错
java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

解法:设置保留的小数位 scale 参数
divide(BigDecimal divisor, int scale, int roundingMode)

@Test
public void divide() {
    BigDecimal value = new BigDecimal("3");
    BigDecimal divide = new BigDecimal("10").divide(value, 2, BigDecimal.ROUND_HALF_UP);
}

2.3 比较

@Test
public void compare() {
    BigDecimal d1 = new BigDecimal("123.0");
    BigDecimal d2 = new BigDecimal("123.00");
    boolean equals = d1.equals(d2); // false, equals() 还会比较小数位scale
    int result = d1.compareTo(d2); // 0
}

2.4 类型转换

@Test
public void convert() {
    BigDecimal value = new BigDecimal("1.1");
    int i = value.intValue();
    double d = value.doubleValue();
}

2.5 BigDecimal.valueOf()

public static BigDecimal valueOf(double val) {
    /*
     * val 会先被转化为字符串类型的对象,可以保证精度不丢失
     */
    return new BigDecimal(Double.toString(val));
}

BigDecimal.valueOf(123.45) 等价于 new BigDecimal("123.45")

3. 小数位

3.1 小数位舍入模式

// 直接舍去
public final static int ROUND_UP = 0;
public final static int ROUND_DOWN = 1;
// 四舍五入
public final static int ROUND_HALF_UP = 4;
模式 描述 示例
ROUND_UP 向远离零的方向舍入 1.5 -> 2,-1.5 -> -2
ROUND_DOWN 向零方向舍入,即截断操作 1.5 -> 1,-1.5 -> -1
ROUND_CEILING 向正无穷方向舍入 对于正数,同ROUND_UP;对于负数,同ROUND_DOWN。它会将结果舍入到最接近的整数,该整数不小于原数
ROUND_FLOOR 向负无穷方向舍入 对于正数,同ROUND_DOWN;对于负数,同ROUND_UP。它会将结果舍入到最接近的整数,该整数不大于原数
ROUND_HALF_UP 四舍五入规则
ROUND_HALF_DOWN 五舍六入,如果舍弃部分>0.5则进位,否则舍弃 1.5 -> 1,2.5 -> 2
ROUND_HALF_EVEN 四舍六入五留双 如果舍弃部分正好为0.5,则如果当前数值是奇数,则向上舍入,如果是偶数,则向下舍入。例如1.5和2.5都会舍入为2
ROUND_UNNECESSARY 表示不需要舍入,如果需要舍入,则抛出ArithmeticException异常

3.2 除法计算

/**
 * 除法运算
 * 示例:12 ÷ 3 = 4 中 12 是被除数, 3 是除数, 因为 12 是被 3 除以的
 *
 * @param dividend  被除数,分子
 * @param divisor   除数,分母
 * @param scale     小数位数,模式:四舍五入
 * @return          两个参数的商
 */
public static Double divide(Long dividend, Long divisor, Integer scale) {
    if (dividend == null || divisor == null || divisor == 0L) {
        return 0D;
    }

    BigDecimal b1 = BigDecimal.valueOf(dividend);
    BigDecimal b2 = BigDecimal.valueOf(divisor);
    return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}

public static Double divide(String dividend, String divisor, Integer scale) {
    return divide(dividend, divisor, scale, BigDecimal.ROUND_HALF_UP);
}

public static Double divide(String v1, String v2, Integer scale, Integer roundingMode) {
    if (StringUtils.isBlank(v1) || StringUtils.isBlank(v2) || "0".equals(v1)) {
        return 0D;
    }

    BigDecimal b1 = new BigDecimal(v1);
    BigDecimal b2 = new BigDecimal(v2);
    return b1.divide(b2, scale, roundingMode).doubleValue();
}

3.3 获取小数位

@Test
public void scale() {
    BigDecimal value = new BigDecimal("123.45");
    int scale = value.scale();
    // scale = 2
}

4. 格式化

@Test
public void format() {
    BigDecimal value = new BigDecimal("1.35");
    DecimalFormat format = new DecimalFormat("0.0");
    System.out.println("0.0" + " ---> " + format.format(value));
    System.out.println("#.#" + " ---> " + new DecimalFormat("#.#").format(value));
    System.out.println("0.000" + " ---> " + new DecimalFormat("0.000").format(value));
    System.out.println("#.###" + " ---> " + new DecimalFormat("#.###").format(value));
}

打印结果:

0.0 ---> 1.4
#.# ---> 1.4
0.000 ---> 1.350
#.### ---> 1.35

4.1 千分位

public static String toThousands(Object value) {
    String pattern;
    if (value instanceof Long) {
        pattern = "#,###";
    } else if (value instanceof Double) {
        pattern = "#,###.00";
    } else {
        return value.toString();
    }
    DecimalFormat decimalFormat = new DecimalFormat(pattern);
    return decimalFormat.format(value);
}

4.2 百分数

public static String toPercent(Double value) {
    DecimalFormat decimalFormat = new DecimalFormat("#0.00%");
    return decimalFormat.format(value);
}

【信息由网络或者个人提供,如有涉及版权请联系COOY资源网邮箱处理】

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容