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,源码显示它会检查小数位数是否相等。
测试两种比较方式的区别
本文地址:https://blog.csdn.net/ChinaLiaoTian/article/details/110950654
上一篇: MySQL修改存储过程的详细步骤
下一篇: golang 限制同一时间的并发量操作
推荐阅读
-
后端将Long类型数据传输到前端出现精度丢失的问题(品优购订单号orderId精度丢失问题)
-
Double类型 通过for循环 精度丢失
-
前端处理后端传回的 Long 类型数据精度丢失
-
easyui 导出execl表格 科学计数法精度丢失问题的解决方案
-
雪花算法等生成Long类型的长Id返回给前端精度丢失问题解决方案
-
springboot中使用Long类型导致前端获取时精度丢失的问题
-
Double类型丢失精度的两种解决方案
-
关于Java中用Double型运算时精度丢失的问题
-
Oracle数据同步接口中,对于NUMBER、DATE类型数据,从resultSet中直接获取造成精度丢失的解决方案
-
Number.MAX_SAFE_INTEGER 后端long类型的ID 导致前端 精度丢失