Android - 金额、利率精确计算BigDecimal,附带工具类

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012246458/article/details/87864202

需求:

Double和float类型,进行加减乘除操作以后,得到的结果小数点后会有好多位。

例如:0.06-0.01 = 0.049999999999999996

所以在涉及到金额或者利率换算时候,必须使用BigDecimal类型进行计算。

BigDecimal:

在这种情况下我们就需要用到java.math包下面的BigDecimal类,BigDecimal主要用于高精度的数据计算,例如计算金额的时候,还有工程测量计算的时候。BigDecimal的提供了add(),subtract(),multiply()和divide()四种方法,分别为加减乘除,一般计算包含小数的用法为

BigDecimal b1 = new BigDecimal(a1);
BigDecimal b2 = new BigDecimal(a2);
System.out.println(b1.subtract(b2).doubleValue());

其中a1和a2的类型可以为String,Double,int,long等等,我在实际用的时候发现了一个问题,当a1和a2的类型为Double的时候,得到的结果仍然丢失了精度,例如:

BigDecimal b1 = new BigDecimal(0.06);
BigDecimal b2 = new BigDecimal(0.01);
System.out.println(b1.subtract(b2).doubleValue());

得到的结果仍然为0.049999999999999996
可是如果参数类型为String,结果就是正确的,就像这样:

BigDecimal b1 = new BigDecimal("0.06");
BigDecimal b2 = new BigDecimal("0.01");
System.out.println(b1.subtract(b2).doubleValue());

得到的结果为0.05。

经过测试发现,原来在new BigDecimal(0.06)的时候,得到b1的结果为0.059999999999999997779553950749686919152736663818359375,而b2的值为0.01000000000000000020816681711721685132943093776702880859375,这时候就已经精度丢失了,最后得到的结果很显然也会丢失精度,而使用new BigDecimal("0.06")得到的b1仍然为0.06。

所以如果大家要对小数进行精确计算的话,new BigDecimal()的参数一定要用String类型的。

工具类:

package com.baofu.yunfutong.util;


import java.math.BigDecimal;

/**
 * Android 精确算法
 * 适用于金额、利率换算
 */
public class BigDecimalUtils {
    /**
     * 提供精确的加法运算
     *
     * @param v1 被加数
     * @param v2 加数
     * @param scale 保留scale 位小数
     * @return 两个参数的和
     */
    public static String add(String v1, String v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("保留的小数位数必须大于零");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.add(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 提供精确的减法运算
     *
     * @param v1 被减数
     * @param v2 减数
     * @param scale 保留scale 位小数
     * @return 两个参数的差
     */
    public static String sub(String v1, String v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("保留的小数位数必须大于零");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.subtract(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 提供精确的乘法运算
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @param scale 保留scale 位小数
     * @return 两个参数的积
     */
    public static String mul(String v1, String v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("保留的小数位数必须大于零");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.multiply(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 提供精确的除法运算。当发生除不尽的情况时,由scale参数指定精度,以后的数字四舍五入
     *
     * @param v1 被除数
     * @param v2 除数
     * @param scale 表示需要精确到小数点以后几位
     * @return 两个参数的商
     */
    public static String div(String v1, String v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("保留的小数位数必须大于零");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 提供精确的小数位四舍五入处理
     *
     * @param v 需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static double round(double v, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("保留的小数位数必须大于零");
        }
        BigDecimal b = new BigDecimal(Double.toString(v));
        return b.setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 提供精确的小数位四舍五入处理
     *
     * @param v 需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static String round(String v, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("保留的小数位数必须大于零");
        }
        BigDecimal b = new BigDecimal(v);
        return b.setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 取余数
     *
     * @param v1 被除数
     * @param v2 除数
     * @param scale 小数点后保留几位
     * @return 余数
     */
    public static String remainder(String v1, String v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("保留的小数位数必须大于零");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.remainder(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 比较大小
     *
     * @param v1 被比较数
     * @param v2 比较数
     * @return 如果v1 大于v2 则 返回true 否则false
     */
    public static boolean compare(String v1, String v2) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        int bj = b1.compareTo(b2);
        if (bj > 0)
            return true;
        else
            return false;
    }
}

猜你喜欢

转载自blog.csdn.net/u012246458/article/details/87864202
今日推荐