欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Double类型丢失精度的两种解决方案

程序员文章站 2022-04-11 09:50:35
继续使用Double类型其实只要在计算时使用封装的工具类,继续使用Double类型精度也不会丢失;转换为BigDecimal时,构造函数采用String那一个。package com.sugarppig.general.utils;import com.sugarppig.common.exception.GeneralException;import java.math.BigDecimal;import java.math.RoundingMode;import java.util.Arr...

1、继续使用Double类型

其实只要在计算时使用封装的工具类,继续使用Double类型精度也不会丢失;转换为BigDecimal时,构造函数采用String那一个。

package com.sugarppig.general.utils;

import com.sugarppig.common.exception.GeneralException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @author SugarPPig
 * @date 2020-12-09 16:05
 * @decription Double 精确计算工具
 */
public class DoubleArithUtil {
    /**
     * 提供精确加法计算的add方法
     *
     * @param value1
     *            被加数
     * @param value2
     *            加数
     * @return 两个参数的和
     */
    public static double add(double value1, double value2) {
        BigDecimal b1 = new BigDecimal(String.valueOf(value1));
        BigDecimal b2 = new BigDecimal(String.valueOf(value2));
        return b1.add(b2).doubleValue();
    }

    /**
     * 提供精确减法运算的sub方法
     *
     * @param value1
     *            被减数
     * @param value2
     *            减数
     * @return 两个参数的差
     */
    public static double sub(double value1, double value2) {
        BigDecimal b1 = new BigDecimal(String.valueOf(value1));
        BigDecimal b2 = new BigDecimal(String.valueOf(value2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供精确乘法运算的mul方法
     *
     * @param value1
     *            被乘数
     * @param value2
     *            乘数
     * @return 两个参数的积
     */
    public static Double mul(Double value1, Double value2) {
        if (value1 == null || value2 == null) {
            return 0d;
        }

        BigDecimal b1 = new BigDecimal(String.valueOf(value1));
        BigDecimal b2 = new BigDecimal(String.valueOf(value2));
        return b1.multiply(b2).doubleValue();
    }

    /**
     * 提供精确的除法运算方法div
     *
     * @param value1
     *            被除数
     * @param value2
     *            除数
     * @param scale
     *            精确范围
     * @return 两个参数的商,默认四舍五入
     * @throws GeneralException
     */
    public static Double div(double value1, double value2, int scale) {
        // 如果精确范围小于0,抛出异常信息
        if (scale < 0) {
            throw new GeneralException("精确度不能小于0");
        }
        if (value2 == 0) {
            return 0d;
        }
        BigDecimal b1 = new BigDecimal(String.valueOf(value1));
        BigDecimal b2 = new BigDecimal(String.valueOf(value2));
        return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
    }

    /**
     * 计算多个值的乘积
     */
    public static Double muls(Double... args) {
        if (args.length < 2) {
            throw new GeneralException("参数至少为2个");
        }
        List<Double> doubles = Arrays.asList(args);
        if (doubles.stream().anyMatch(Objects::isNull)) {
            return 0d;
        }
        return doubles.parallelStream().reduce(1d, DoubleArithUtil::mul);
    }

    /**
     * 计算多个值的和
     */
    public static Double adds(Double... args) {
        if (args.length < 2) {
            throw new GeneralException("参数至少为2个");
        }
        List<Double> doubles = Arrays.asList(args);
        if (doubles.stream().anyMatch(Objects::isNull)) {
            return 0d;
        }
        return doubles.parallelStream().reduce(0d, DoubleArithUtil::add);
    }

    /**
     * 计算多个值的和,元素为null时记为0d参与运算
     */
    public static Double addsNull(Double... args) {
        if (args.length < 2) {
            throw new GeneralException("参数至少为2个");
        }
        List<Double> doubles = Arrays.asList(args);
        return doubles.parallelStream().map(e -> e == null ? 0d : e).reduce(0d, DoubleArithUtil::add);
    }
}

2、将Double类型改为BigDecimal类型

BigDecimal工具类,将Double的工具类稍微改动了下。

package com.sugarppig.general.utils;

import com.sugarppig.common.exception.GeneralException;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @author SugarPPig
 * @date 2020-12-10 10:03
 * @decription BigDecimal 精确计算工具
 */
public class BigDecimalArithUtil {
    /**
     * 提供精确加法计算的add方法
     *
     * @param value1
     *            被加数
     * @param value2
     *            加数
     * @return 两个参数的和
     */
    public static BigDecimal add(BigDecimal value1, BigDecimal value2) {
        return value1.add(value2);
    }

    /**
     * 提供精确减法运算的sub方法
     *
     * @param value1
     *            被减数
     * @param value2
     *            减数
     * @return 两个参数的差
     */
    public static BigDecimal sub(BigDecimal value1, BigDecimal value2) {
        return value1.subtract(value2);
    }

    /**
     * 提供精确乘法运算的mul方法
     *
     * @param value1
     *            被乘数
     * @param value2
     *            乘数
     * @return 两个参数的积
     */
    public static BigDecimal mul(BigDecimal value1, BigDecimal value2) {
        if (value1 == null || value2 == null) {
            return BigDecimal.ZERO;
        }

        return value1.multiply(value2);
    }

    /**
     * 提供精确的除法运算方法div
     *
     * @param value1
     *            被除数
     * @param value2
     *            除数
     * @param scale
     *            精确范围
     * @return 两个参数的商,默认四舍五入
     * @throws GeneralException
     */
    public static BigDecimal div(BigDecimal value1, BigDecimal value2, int scale) {
        // 如果精确范围小于0,抛出异常信息
        if (scale < 0) {
            throw new GeneralException("精确度不能小于0");
        }
        if (value2.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }
        return value1.divide(value2, scale, RoundingMode.HALF_UP);
    }

    /**
     * 计算多个值的乘积
     */
    public static BigDecimal muls(BigDecimal... args) {
        if (args.length < 2) {
            throw new GeneralException("参数至少为2个");
        }
        List<BigDecimal> bigDecimals = Arrays.asList(args);
        if (bigDecimals.stream().anyMatch(Objects::isNull)) {
            return BigDecimal.ZERO;
        }
        return bigDecimals.parallelStream().reduce(BigDecimal.ONE, ArithUtil::mul);
    }

    /**
     * 计算多个值的和
     */
    public static BigDecimal adds(BigDecimal... args) {
        if (args.length < 2) {
            throw new GeneralException("参数至少为2个");
        }
        List<BigDecimal> BigDecimals = Arrays.asList(args);
        if (BigDecimals.stream().anyMatch(Objects::isNull)) {
            return BigDecimal.ZERO;
        }
        return BigDecimals.parallelStream().reduce(BigDecimal.ZERO, ArithUtil::add);
    }

    /**
     * 计算多个值的和,元素为null时记为0参与运算
     */
    public static BigDecimal addsNull(BigDecimal... args) {
        if (args.length < 2) {
            throw new GeneralException("参数至少为2个");
        }
        List<BigDecimal> BigDecimals = Arrays.asList(args);
        return BigDecimals.parallelStream().map(e -> e == null ? BigDecimal.ZERO : e).reduce(BigDecimal.ZERO,
            ArithUtil::add);
    }
}

注意!!!使用BigDecimal比较两个数,值的大小时,一定要使用compareTo,不要用equals,源码显示它会检查小数位数是否相等。
Double类型丢失精度的两种解决方案
测试两种比较方式的区别
Double类型丢失精度的两种解决方案

本文地址:https://blog.csdn.net/ChinaLiaoTian/article/details/110950654

相关标签: java