关于数据精确计算,以及四舍五入中,你所不知道的坑


在java中, 使用float或者double做基本的加减乘除可能不会得到精确的值,这是因为这些数值类型在计算的时候都会丢失精度,那么如果才能做到精确计算呢,在java中提供了一个类专门用来做精确计算的,那就是BigDecimal,但是很多人在使用的过程中却发现并不能如愿的实现精确计算,这是为什么呢,下面我会做讲解,现在先贴上一段代码,本代码中还包涵了一部分数据格式化方法:

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;

/**
 * @author: xiewenliang
 * @Filename:
 * @Description:
 * @Copyright: Copyright (c) 2017 Tuandai Inc. All rights reserved.
 * @date: 2017/4/13 16:00
 */

public class RefinedCalculation {

    /**
     * 加法精确计算
     *
     * @param number1 数据类型1
     * @param number2 数据类型2
     * @return 计算结果
     */
    public static BigDecimal addition(Number number1, Number number2) {
        BigDecimal bigDecimal1 = new BigDecimal(String.valueOf(number1));
        BigDecimal bigDecimal2 = new BigDecimal(String.valueOf(number2));
        return bigDecimal1.add(bigDecimal2);
    }

    /**
     * 减法精确计算
     *
     * @param number1 数据类型1
     * @param number2 数据类型2
     * @return 计算结果
     */
    public static BigDecimal subtraction(Number number1, Number number2) {
        BigDecimal bigDecimal1 = new BigDecimal(String.valueOf(number1));
        BigDecimal bigDecimal2 = new BigDecimal(String.valueOf(number2));
        return bigDecimal1.subtract(bigDecimal2);
    }

    /**
     * 乘法精确计算
     *
     * @param number1 数据类型1
     * @param number2 数据类型2
     * @return 计算结果
     */
    public static BigDecimal multiplication(Number number1, Number number2) {
        BigDecimal bigDecimal1 = new BigDecimal(String.valueOf(number1));
        BigDecimal bigDecimal2 = new BigDecimal(String.valueOf(number2));
        return bigDecimal1.multiply(bigDecimal2);
    }

    /**
     * 除法精确计算
     *
     * @param number1 数据类型1
     * @param number2 数据类型2
     * @param scale   小数点精确位数
     * @return 计算结果
     */
    public static BigDecimal division(Number number1, Number number2, int scale) {
        return division(number1, number2, scale, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 除法精确计算
     *
     * @param number1      数据类型1
     * @param number2      数据类型2
     * @param scale        小数点精确位数
     * @param roundingMode 舍入模式
     * @return 计算结果
     */
    public static BigDecimal division(Number number1, Number number2, int scale, int roundingMode) {
        BigDecimal bigDecimal1 = new BigDecimal(String.valueOf(number1));
        BigDecimal bigDecimal2 = new BigDecimal(String.valueOf(number2));
        return bigDecimal1.divide(bigDecimal2, scale, roundingMode);
    }

    /**
     * 四舍五入
     *
     * @param number 数据类型
     * @param scale  小数点精确位数
     * @return 计算结果
     */
    public static BigDecimal round(Number number, int scale) {
        return round(number, scale, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 四舍五入
     *
     * @param number       数据类型
     * @param scale        小数点精确位数
     * @param roundingMode 舍入模式
     * @return 计算结果
     */
    public static BigDecimal round(Number number, int scale, int roundingMode) {
        return new BigDecimal(String.valueOf(number)).setScale(scale, roundingMode);
    }

    /**
     * 四舍五入(保留两位小数,不足补零,舍入模式为四舍五入)
     *
     * @param number 数据类型
     * @return 计算结果
     */
    public static String roundDecimalFormat(Number number) {
        return roundDecimalFormat(number, "#,##0.00");
    }

    /**
     * 四舍五入(格式化模式可自行定义,舍入模式为四舍五入)
     *
     * @param number  数据类型
     * @param pattern 格式化模式
     * @return 计算结果
     */
    public static String roundDecimalFormat(Number number, String pattern) {
        return roundDecimalFormat(number, pattern, RoundingMode.HALF_UP);
    }

    /**
     * 四舍五入(格式化模式可自行定义,舍入模式可自行定义)
     *
     * @param number       数据类型
     * @param pattern      格式化模式
     * @param roundingMode 舍入模式
     * @return 计算结果
     */
    public static String roundDecimalFormat(Number number, String pattern, RoundingMode roundingMode) {
        DecimalFormat decimalFormat = new DecimalFormat(pattern, new DecimalFormatSymbols(Locale.CHINA));
        decimalFormat.setRoundingMode(roundingMode);
        return decimalFormat.format(String.valueOf(number));
    }
}

前面说过,很多人在使用BigDecimal的时候还是不能做到精确计算,这还是因为精度丢失的问题,大家有注意到吗 ,我上述代码中,在new BigDecimal的时候都会把值先转成String类型,问题的症结就在这里了,我们传入的如果是数值类型,在参与计算之前会强行转换从而丢失精度,所以得到的结果会不正确的,使用BigDecimal只需记住一点,构造参数一定要是字符串类型。

接下来说说数据格式化的方法,大家有看到 ,对数据做舍入处理的时候有多种方法, 这里介绍第二种方法可能遇到的坑, 当系统语言设置为Afrikaans时,使用DecimalFormat格式化数据的时候就会发现点号会变成逗号,从而导致数据出现问题,目前有一个解决办法就是在创建DecimalFormat的时候,构造函数中传入语言,就可以避免此种情况了。

好了,坑就介绍到这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值