package com.vstsoft.common.util; import java.math.BigDecimal; import java.text.DecimalFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @Comments : 由于Java的简单类型不能够精确的对浮点数进行运算, 这个工具类提供精确的浮点数运算,包括加减乘除和四舍五入。 */ public class ArithUtil { // 默认除法运算精度 private static final int DEFAULT_DIV_SCALE = 10; private final static Logger logger = LoggerFactory.getLogger(ArithUtil.class); /** * 提供精确的加法运算。 * * @param v1 * @param v2 * @return 两个参数的和 */ public static BigDecimal add(BigDecimal b1, BigDecimal b2) { return b1.add(b2); } public static BigDecimal add(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return add(b1, b2); } /** * 提供精确的减法运算。 * * @param v1 * @param v2 * @return 两个参数的差 */ public static BigDecimal subtract(BigDecimal b1, BigDecimal b2) { return b1.subtract(b2); } public static BigDecimal subtract(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.subtract(b2); } /** * 提供精确的乘法运算。 * * @param v1 * @param v2 * @return 两个参数的积 */ public static BigDecimal multiply(BigDecimal b1, BigDecimal b2) { return b1.multiply(b2); } public static BigDecimal multiply(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.multiply(b2); } /** * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入,舍入模式采用ROUND_HALF_EVEN * * @param v1 * 被除数 * @param v2 * 除数 * @return 两个参数的商 */ public static BigDecimal divide(BigDecimal b1, BigDecimal b2) { return divide(b1, b2, DEFAULT_DIV_SCALE); } public static BigDecimal divide(double v1, double v2) { return divide(v1, v2, DEFAULT_DIV_SCALE); } /** * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。舍入模式采用ROUND_HALF_EVEN * * @param v1 * 被除数 * @param v2 * 除数 * @param scale * 表示需要精确到小数点以后几位。 * @return 两个参数的商 */ public static BigDecimal divide(BigDecimal b1, BigDecimal b2, int scale) { return divide(b1, b2, scale, BigDecimal.ROUND_HALF_EVEN); } public static BigDecimal divide(double v1, double v2, int scale) { return divide(v1, v2, scale, BigDecimal.ROUND_HALF_EVEN); } /** * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。舍入模式采用用户指定舍入模式 * * @param v1 * 被除数 * @param v2 * 除数 * @param scale * 表示需要精确到小数点以后几位 * @param round_mode * 表示用户指定的舍入模式 * @return 两个参数的商 */ public static BigDecimal divide(BigDecimal b1, BigDecimal b2, int scale, int round_mode) { if (scale < 0) { throw new IllegalArgumentException("The scale must be a positive integer or zero"); } return b1.divide(b2, scale, round_mode); } public static BigDecimal divide(double v1, double v2, int scale, int round_mode) { if (scale < 0) { throw new IllegalArgumentException("The scale must be a positive integer or zero"); } BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.divide(b2, scale, round_mode); } /** * 提供保留两位小数的四舍五入处理,舍入模式采用ROUND_HALF_EVEN * * @param v * 需要四舍五入的数字 * @param scale * 小数点后保留几位 * @return 四舍五入后的结果 */ public static BigDecimal round(BigDecimal b) { return round(b, 2); } /** * 提供精确的小数位四舍五入处理,舍入模式采用ROUND_HALF_EVEN * * @param v * 需要四舍五入的数字 * @param scale * 小数点后保留几位 * @return 四舍五入后的结果 */ public static BigDecimal round(BigDecimal b, int scale) { return round(b, scale, BigDecimal.ROUND_HALF_EVEN); } /** * 提供精确的小数位四舍五入处理 * * @param v * 需要四舍五入的数字 * @param scale * 小数点后保留几位 * @param round_mode * 指定的舍入模式 * @return 四舍五入后的结果 */ public static BigDecimal round(BigDecimal b, int scale, int round_mode) { if (scale < 0) { logger.error(StaticUtil.UTILERROR, "scale:" + scale + ",the scale must be a positive integer or zero"); throw new IllegalArgumentException("The scale must be a positive integer or zero"); } return b.setScale(scale, round_mode); } public static void main(String[] args) { BigDecimal b1 = new BigDecimal("100"); BigDecimal b2 = new BigDecimal("1.765"); BigDecimal b3 = new BigDecimal("1.65"); BigDecimal b4 = new BigDecimal("7"); // 精确除法运算 logger.info(divide(b1, b4).toString()); logger.info(divide(b1, b4, 1).toString()); logger.info(round(b2, 2, BigDecimal.ROUND_HALF_EVEN).toString()); logger.info(round(b2, 2, BigDecimal.ROUND_HALF_UP).toString()); logger.info(round(b2, 2, BigDecimal.ROUND_HALF_DOWN).toString()); logger.info(round(b3, 1, BigDecimal.ROUND_HALF_EVEN).toString()); logger.info(round(b3, 1, BigDecimal.ROUND_HALF_UP).toString()); logger.info(round(b3, 1, BigDecimal.ROUND_HALF_DOWN).toString()); // 数学运算在实际中存在的问题 /** * 0.060000000000000005 0.5800000000000001 401.49999999999994 * 1.2329999999999999 */ logger.info("错误的结果:"); logger.info(0.05 + 0.01 + ""); logger.info(1.0 - 0.42 + ""); logger.info(4.015 * 100 + ""); logger.info(123.3 / 100 + ""); logger.info("精确计算的结果:"); logger.info(ArithUtil.add(new BigDecimal("0.056789123446"), new BigDecimal("0.01234566789")).toString()); logger.info(ArithUtil.subtract(new BigDecimal("1.012345678912"), new BigDecimal("0.42345689127")).toString()); logger.info(ArithUtil.multiply(new BigDecimal("4.0156789"), new BigDecimal("100.12345")).toString()); logger.info(ArithUtil.divide(new BigDecimal("123.3"), new BigDecimal("100")).toString()); /** * 输入结果为 504.549999999999982946974341757595539093017578125 实际结果应为 504.55 */ logger.info("BigDecimal 的不精确计算问题:"); BigDecimal bg1 = new BigDecimal(100.91); BigDecimal bg2 = new BigDecimal(5); BigDecimal bg3 = bg1.multiply(bg2); logger.info(bg3 + ""); DecimalFormat df = new DecimalFormat("¥0,000.00"); logger.info("精确计算的结果:"); BigDecimal bg4 = multiply(new BigDecimal("1000000000.91"), new BigDecimal("5")); logger.info(ArithUtil.round(bg4).toString()); BigDecimal bg5 = multiply(new BigDecimal("10000000"), new BigDecimal("9999999")); logger.info(ArithUtil.round(bg5).toString()); logger.info("***************************************************"); } }
最近下载更多
无名者 LV2
2022年5月7日
luohaipeng LV23
2019年12月3日
低调人 LV38
2019年8月4日
2428902929 LV1
2019年6月11日
DawnWalker LV19
2018年12月14日
银风落幻 LV2
2018年1月7日
865229936 LV6
2017年7月18日
cityhunter LV5
2017年2月10日
司马文若 LV1
2016年12月4日
wq1234567pw LV2
2016年6月26日
最近浏览更多
无名者 LV2
2022年5月7日
2196316269 LV10
2021年2月24日
小小123123 LV1
2020年11月17日
jachyn LV6
2020年9月9日
kinggode LV14
2020年7月28日
飞翔的天空
2020年6月28日
暂无贡献等级
低调人 LV38
2019年8月4日
2428902929 LV1
2019年6月11日
DawnWalker LV19
2018年12月14日
xp9522 LV9
2018年8月13日