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));
}
运算结果:
要进行精确的加减乘除请使用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));
}
运算结果: