BigDecimal实现精确的加减乘除

    float和double类型的主要设计目的是为了科学计算和工程计算。它们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的。然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合。float和double类型对于货币计算尤为不合适,因为要让一个float或者double精确地表示0.1(或者10的任何负数次方值)是不可能的。下图列举一些加减乘除计算出现的问题:

public static void main(String[] args) {
	System.out.println("double加法:" + (10.2 + 20.9));
	System.out.println("double减法:" + (1.0 - 0.9));
	System.out.println("double乘法:" + (5.4 * 3.0));
	System.out.println("double除法:" + (0.6 / 0.2));
}

运算结果:

162513_Qy66_2279906.png

要进行精确的加减乘除请使用java.math.BigDecimal提供的方法,下面的工具类是根据BigDecimal编写的:

import java.math.BigDecimal;

/**
 * 
 * @Description : 精确计算
 * @time 创建时间 : 2016年2月18日
 * @author : DeanFan
 * @Copyright (c) 2016
 * @version
 */
public class MathUtils {
	/**
	 * 
	 * Description : 加法运算,保留精度(四舍五入)
	 * @param v1
	 * @param v2
	 * @param scale 精度
	 * @author DeanFan
	 */
	public static double add(double v1, double v2, int scale) {
		return MathUtils.add(Double.toString(v1), Double.toString(v2), scale);
	}
	
	/**
	 * 
	 * Description : 加法运算,保留精度(四舍五入)
	 * @param v1
	 * @param v2
	 * @param scale 精度
	 * @author DeanFan
	 */
	public static double add(String v1, String v2, int scale) {
		return MathUtils.add(v1, v2, scale, BigDecimal.ROUND_HALF_UP);
	}
	
	/**
	 * 
	 * Description : 加法运算,按舍入类别保留精度
	 * @param v1
	 * @param v2
	 * @param scale 精度
	 * @param roundType 舍入类别<br>
	 * 例:BigDecimal.ROUND_HALF_UP
	 * @author DeanFan
	 */
	public static double add(double v1, double v2, int scale, int roundType) {
		return MathUtils.add(Double.toString(v1), Double.toString(v2), scale, roundType);
	}
	
	/**
	 * 
	 * Description : 加法运算,按舍入类别保留精度
	 * @param v1
	 * @param v2
	 * @param scale 精度
	 * @param roundType 舍入类别<br>
	 * 例:BigDecimal.ROUND_HALF_UP
	 * @author DeanFan
	 */
	public static double add(String v1, String v2, int scale, int roundType) {
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.add(b2).setScale(scale, roundType).doubleValue();
	}

	/**
	 * 
	 * Description : 减法运算,保留精度(四舍五入)
	 * @param v1 被减数
	 * @param v2 减数
	 * @param scale 精度
	 * @author DeanFan
	 */
	public static double subtract(double v1, double v2, int scale) {
		return MathUtils.subtract(Double.toString(v1), Double.toString(v2), scale);
	}
	
	/**
	 * 
	 * Description : 减法运算,保留精度(四舍五入)
	 * @param v1 被减数
	 * @param v2 减数
	 * @param scale 精度
	 * @param roundType 舍入类别<br>
	 * 例:BigDecimal.ROUND_HALF_UP
	 * @author DeanFan
	 */
	public static double subtract(String v1, String v2, int scale) {
		return MathUtils.subtract(v1, v2, scale, BigDecimal.ROUND_HALF_UP);
	}
	
	/**
	 * 
	 * Description : 减法运算,按舍入类别保留精度
	 * @param v1 被减数
	 * @param v2 减数
	 * @param scale 精度
	 * @param roundType 舍入类别<br>
	 * 例:BigDecimal.ROUND_HALF_UP
	 * @author DeanFan
	 */
	public static double subtract(double v1, double v2, int scale, int roundType) {
		return MathUtils.subtract(Double.toString(v1), Double.toString(v2), scale, roundType);
	}
	
	/**
	 * 
	 * Description : 减法运算,按舍入类别保留精度
	 * @param v1 被减数
	 * @param v2 减数
	 * @param scale 精度
	 * @author DeanFan
	 */
	public static double subtract(String v1, String v2, int scale, int roundType) {
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.subtract(b2).setScale(scale, roundType).doubleValue();
	}

	/**
	 * 
	 * Description : 乘法运算,保留精度(四舍五入)
	 * @param v1
	 * @param v2
	 * @param scale 精度
	 * @author DeanFan
	 */
	public static double multiply(double v1, double v2, int scale) {
		return MathUtils.multiply(Double.toString(v1), Double.toString(v2), scale);
	}
	
	/**
	 * 
	 * Description : 乘法运算,保留精度(四舍五入)
	 * @param v1
	 * @param v2
	 * @param scale 精度
	 * @author DeanFan
	 */
	public static double multiply(String v1, String v2, int scale) {
		return MathUtils.multiply(v1, v2, scale, BigDecimal.ROUND_HALF_UP);
	}
	
	/**
	 * 
	 * Description : 乘法运算,按舍入类别保留精度
	 * @param v1
	 * @param v2
	 * @param scale 精度
	 * @param roundType 舍入类别<br>
	 * 例:BigDecimal.ROUND_HALF_UP
	 * @author DeanFan
	 */
	public static double multiply(double v1, double v2, int scale, int roundType) {
		return MathUtils.multiply(Double.toString(v1), Double.toString(v2), scale, roundType);
	}
	
	/**
	 * 
	 * Description : 乘法运算,按舍入类别保留精度
	 * @param v1
	 * @param v2
	 * @param scale 精度
	 * @param roundType 舍入类别<br>
	 * 例:BigDecimal.ROUND_HALF_UP
	 * @author DeanFan
	 */
	public static double multiply(String v1, String v2, int scale, int roundType) {
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.multiply(b2).setScale(scale, roundType).doubleValue();
	}

	/**
	 * 
	 * Description : 除法运算,保留精度(四舍五入)
	 * @param v1  被除数
	 * @param v2 除数
	 * @param scale 精度
	 * @author DeanFan
	 */
	public static double divide(double v1, double v2, int scale) {
		return MathUtils.divide(Double.toString(v1), Double.toString(v2), scale);
	}
	
	/**
	 * 
	 * Description : 除法运算,保留精度(四舍五入)
	 * @param v1  被除数
	 * @param v2 除数
	 * @param scale 精度
	 * @author DeanFan
	 */
	public static double divide(String v1, String v2, int scale) {
		return MathUtils.divide(v1, v2, scale, BigDecimal.ROUND_HALF_UP);
	}
	
	/**
	 * 
	 * Description : 除法运算,按舍入类别保留精度
	 * @param v1  被除数
	 * @param v2 除数
	 * @param scale 精度
	 * @param roundType 舍入类别<br>
	 * 例:BigDecimal.ROUND_HALF_UP
	 * @author DeanFan
	 */
	public static double divide(double v1, double v2, int scale, int roundType) {
		return MathUtils.divide(Double.toString(v1), Double.toString(v2), scale, roundType);
	}
	
	/**
	 * 
	 * Description : 除法运算,按舍入类别保留精度
	 * @param v1  被除数
	 * @param v2 除数
	 * @param scale 精度
	 * @param roundType 舍入类别<br>
	 * 例:BigDecimal.ROUND_HALF_UP
	 * @author DeanFan
	 */
	public static double divide(String v1, String v2, int scale, int roundType) {
		if (Double.valueOf(v2) == 0.0) {
			throw new ArithmeticException("/ by zero");
		}
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.divide(b2, scale, roundType).doubleValue();
	}

	/**
	 * 
	 * Description : 四舍五入
	 * @param v
	 * @param scale 精度
	 * @author DeanFan
	 */
	public static double round(double v, int scale) {
		return MathUtils.round(Double.toString(v), scale);
	}
	
	/**
	 * 
	 * Description : 四舍五入
	 * @param v
	 * @param scale 精度
	 * @author DeanFan
	 */
	public static double round(String v, int scale) {
		return MathUtils.round(v, scale, BigDecimal.ROUND_HALF_UP);
	}
	
	/**
	 * 
	 * Description : 按舍入类别保留精度
	 * @param v
	 * @param scale 精度
	 * @param roundType 舍入类别<br>
	 * 例:BigDecimal.ROUND_HALF_UP
	 * @author DeanFan
	 */
	public static double round(double v, int scale, int roundType) {
		return MathUtils.round(Double.toString(v), scale, roundType);
	}
	
	/**
	 * 
	 * Description : 按舍入类别保留精度
	 * @param v
	 * @param scale 精度
	 * @param roundType 舍入类别<br>
	 * 例:BigDecimal.ROUND_HALF_UP
	 * @author DeanFan
	 */
	public static double round(String v, int scale, int roundType) {
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		BigDecimal b = new BigDecimal(v);
		return b.setScale(scale, roundType).doubleValue();
	}
	
}

利用工具类运算:

public static void main(String[] args) {
	int scale = 2;
	System.out.println("double加法:" + add(10.2, 20.9, scale));
	System.out.println("double减法:" + subtract(1.0, 0.9, scale));
	System.out.println("double乘法:" + multiply(5.4, 3.0, scale));
	System.out.println("double除法:" + divide(0.6, 0.2, scale));
}

运算结果:

163130_viAv_2279906.png

转载于:https://my.oschina.net/fandean/blog/753850

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值