|
|
|
@ -0,0 +1,168 @@
|
|
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* https://www.mall4j.com/
|
|
|
|
|
*
|
|
|
|
|
* 未经允许,不可做商业用途!
|
|
|
|
|
*
|
|
|
|
|
* 版权所有,侵权必究!
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package com.yami.shop.common.util;
|
|
|
|
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
|
|
import java.math.RoundingMode;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 算术运算工具类,用于提供精确的数值计算功能,避免浮点数计算时因精度问题产生误差。
|
|
|
|
|
* 该类主要针对double类型以及BigDecimal类型的数值进行加、减、乘、除和四舍五入等常见算术运算操作。
|
|
|
|
|
* @author lanhai
|
|
|
|
|
*/
|
|
|
|
|
public class Arith {
|
|
|
|
|
/**
|
|
|
|
|
* 默认除法运算精度,即当调用无指定精度的div方法时,除法运算结果将精确到小数点后2位,
|
|
|
|
|
* 后续的数字按照相应的舍入规则进行处理(此处为HALF_EVEN舍入模式)。
|
|
|
|
|
*/
|
|
|
|
|
private static final int DEF_DIV_SCALE = 2;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 将构造函数私有化,防止外部实例化该类,因为这个类的设计目的是作为工具类,提供静态方法供调用,
|
|
|
|
|
* 不需要创建类的实例对象,所以禁止外部实例化它。
|
|
|
|
|
*/
|
|
|
|
|
private Arith() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 提供精确的加法运算。
|
|
|
|
|
* 该方法接收两个double类型的参数,将它们转换为BigDecimal类型后进行精确加法运算,
|
|
|
|
|
* 最后返回计算结果的double值,这样可以避免直接使用double进行加法运算时可能出现的精度丢失问题。
|
|
|
|
|
*
|
|
|
|
|
* @param v1 被加数,即参与加法运算的第一个数值。
|
|
|
|
|
* @param v2 加数,即参与加法运算的第二个数值。
|
|
|
|
|
* @return 两个参数的和,以double类型返回精确计算后的结果。
|
|
|
|
|
*/
|
|
|
|
|
public static double add(double v1, double v2) {
|
|
|
|
|
// 必须转换成String,因为BigDecimal的构造函数建议使用基于字符串的构造方式来避免精度问题,
|
|
|
|
|
// 如果直接使用double类型传入构造函数,在某些情况下可能会出现精度丢失。
|
|
|
|
|
String s1 = Double.toString(v1);
|
|
|
|
|
String s2 = Double.toString(v2);
|
|
|
|
|
BigDecimal b1 = new BigDecimal(s1);
|
|
|
|
|
BigDecimal b2 = new BigDecimal(s2);
|
|
|
|
|
return b1.add(b2).doubleValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 提供精确的减法运算。
|
|
|
|
|
* 与加法运算类似,接收两个double类型的参数,先转换为BigDecimal类型,再进行精确的减法操作,
|
|
|
|
|
* 最后返回结果的double值,确保减法运算的精度准确性。
|
|
|
|
|
*
|
|
|
|
|
* @param v1 被减数,参与减法运算的第一个数值,从中减去另一个数值。
|
|
|
|
|
* @param v2 减数,参与减法运算的第二个数值,用于从被减数中减去。
|
|
|
|
|
* @return 两个参数的差,以double类型返回精确计算后的结果。
|
|
|
|
|
*/
|
|
|
|
|
public static double sub(double v1, double v2) {
|
|
|
|
|
String s1 = Double.toString(v1);
|
|
|
|
|
String s2 = Double.toString(v2);
|
|
|
|
|
BigDecimal b1 = new BigDecimal(s1);
|
|
|
|
|
BigDecimal b2 = new BigDecimal(s2);
|
|
|
|
|
return b1.subtract(b2).doubleValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 提供精确的乘法运算。
|
|
|
|
|
* 同样,把传入的两个double类型参数转换为BigDecimal类型后进行乘法运算,
|
|
|
|
|
* 以保证乘法计算结果的精度符合预期,最后返回double类型的结果值。
|
|
|
|
|
*
|
|
|
|
|
* @param v1 被乘数,参与乘法运算的第一个数值,与另一个数值相乘。
|
|
|
|
|
* @param v2 乘数,参与乘法运算的第二个数值,用于和被乘数相乘。
|
|
|
|
|
* @return 两个参数的积,以double类型返回精确计算后的结果。
|
|
|
|
|
*/
|
|
|
|
|
public static double mul(double v1, double v2) {
|
|
|
|
|
String s1 = Double.toString(v1);
|
|
|
|
|
String s2 = Double.toString(v2);
|
|
|
|
|
BigDecimal b1 = new BigDecimal(s1);
|
|
|
|
|
BigDecimal b2 = new BigDecimal(s2);
|
|
|
|
|
return b1.multiply(b2).doubleValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到小数点以后10位,以后的数字四舍五入。
|
|
|
|
|
* 这里实际调用了另一个带有精度参数的div方法,并传入默认的精度值(DEF_DIV_SCALE),
|
|
|
|
|
* 以实现默认精度下的除法运算功能。
|
|
|
|
|
*
|
|
|
|
|
* @param v1 被除数,参与除法运算的第一个数值,作为被除的对象。
|
|
|
|
|
* @param v2 除数,参与除法运算的第二个数值,用于除被除数。
|
|
|
|
|
* @return 两个参数的商,以double类型返回按照默认精度进行四舍五入后的结果。
|
|
|
|
|
*/
|
|
|
|
|
public static double div(double v1, double v2) {
|
|
|
|
|
return div(v1, v2, DEF_DIV_SCALE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指定精度,以后的数字四舍五入。
|
|
|
|
|
* 首先会对传入的参数进行合法性校验,如果指定的精度scale小于0,则抛出异常,
|
|
|
|
|
* 因为精度应该是正整数或者0,表示小数点后的保留位数。然后将传入的double类型参数转换为BigDecimal类型,
|
|
|
|
|
* 使用指定的精度和HALF_EVEN舍入模式进行除法运算,最后返回double类型的商。
|
|
|
|
|
*
|
|
|
|
|
* @param v1 被除数,参与除法运算的第一个数值,作为被除的对象。
|
|
|
|
|
* @param v2 除数,参与除法运算的第二个数值,用于除被除数。
|
|
|
|
|
* @param scale 表示需要精确到小数点以后几位,用于指定除法运算结果的精度。
|
|
|
|
|
* @return 两个参数的商,以double类型返回按照指定精度进行四舍五入后的结果。
|
|
|
|
|
*/
|
|
|
|
|
public static double div(double v1, double v2, int scale) {
|
|
|
|
|
if (scale < 0) {
|
|
|
|
|
throw new IllegalArgumentException("The scale must be a positive integer or zero");
|
|
|
|
|
}
|
|
|
|
|
String s1 = Double.toString(v1);
|
|
|
|
|
String s2 = Double.toString(v2);
|
|
|
|
|
BigDecimal b1 = new BigDecimal(s1);
|
|
|
|
|
BigDecimal b2 = new BigDecimal(s2);
|
|
|
|
|
return b1.divide(b2, scale, RoundingMode.HALF_EVEN).doubleValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 提供精确的小数位四舍五入处理。
|
|
|
|
|
* 先对传入的参数进行合法性校验,要求scale(小数点后保留位数)不能小于0,
|
|
|
|
|
* 然后将需要四舍五入的数字转换为BigDecimal类型,再通过与表示数值1的BigDecimal对象进行除法运算,
|
|
|
|
|
* 按照指定的scale和HALF_EVEN舍入模式进行四舍五入,最后返回处理后的double类型结果。
|
|
|
|
|
*
|
|
|
|
|
* @param v 需要四舍五入的数字,以double类型传入。
|
|
|
|
|
* @param scale 小数点后保留几位,用于指定四舍五入的精度要求。
|
|
|
|
|
* @return 四舍五入后的结果,以double类型返回经过处理后的数值。
|
|
|
|
|
*/
|
|
|
|
|
public static double round(double v, int scale) {
|
|
|
|
|
if (scale < 0) {
|
|
|
|
|
throw new IllegalArgumentException("The scale must be a positive integer or zero");
|
|
|
|
|
}
|
|
|
|
|
String s = Double.toString(v);
|
|
|
|
|
BigDecimal b = new BigDecimal(s);
|
|
|
|
|
BigDecimal one = new BigDecimal("1");
|
|
|
|
|
return b.divide(one, scale, RoundingMode.HALF_EVEN).doubleValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 重载的加法运算方法,用于对三个BigDecimal类型的数值进行相加操作,
|
|
|
|
|
* 最后返回相加结果的double值,方便在需要对多个BigDecimal数值求和时使用。
|
|
|
|
|
*
|
|
|
|
|
* @param bigDecimal 参与加法运算的第一个BigDecimal数值。
|
|
|
|
|
* @param bigDecimal2 参与加法运算的第二个BigDecimal数值。
|
|
|
|
|
* @param bigDecimal3 参与加法运算的第三个BigDecimal数值。
|
|
|
|
|
* @return 三个参数的和,以double类型返回精确计算后的结果。
|
|
|
|
|
*/
|
|
|
|
|
public static double add(BigDecimal bigDecimal, BigDecimal bigDecimal2, BigDecimal bigDecimal3) {
|
|
|
|
|
return bigDecimal.add(bigDecimal2).add(bigDecimal3).doubleValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 另一个重载的加法运算方法,用于对两个BigDecimal类型的数值进行相加操作,
|
|
|
|
|
* 并返回相加结果的double值,满足不同场景下对两个BigDecimal数值求和的需求。
|
|
|
|
|
*
|
|
|
|
|
* @param preDepositPrice 参与加法运算的第一个BigDecimal数值,通常可以理解为预存金额之类的数值(具体含义取决于业务场景)。
|
|
|
|
|
* @param finalPrice 参与加法运算的第二个BigDecimal数值,通常可以理解为最终金额之类的数值(具体含义取决于业务场景)。
|
|
|
|
|
* @return 两个参数的和,以double类型返回精确计算后的结果。
|
|
|
|
|
*/
|
|
|
|
|
public static double add(BigDecimal preDepositPrice, BigDecimal finalPrice) {
|
|
|
|
|
return preDepositPrice.add(finalPrice).doubleValue();
|
|
|
|
|
}
|
|
|
|
|
}
|